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

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 (96) hide show
  1. package/dist/esm/companion/application-documentation/application-connection-documentation.d.ts +25 -1
  2. package/dist/esm/companion/application-documentation/application-connection-documentation.d.ts.map +1 -1
  3. package/dist/esm/companion/application-documentation/application-connection-documentation.js +28 -1
  4. package/dist/esm/companion/application-documentation/application-connection-documentation.js.map +1 -1
  5. package/dist/esm/companion/application-documentation/application-domain-documentation.d.ts +133 -0
  6. package/dist/esm/companion/application-documentation/application-domain-documentation.d.ts.map +1 -0
  7. package/dist/esm/companion/application-documentation/application-domain-documentation.js +243 -0
  8. package/dist/esm/companion/application-documentation/application-domain-documentation.js.map +1 -0
  9. package/dist/esm/companion/application-documentation/application-integration-documentation.d.ts.map +1 -1
  10. package/dist/esm/companion/application-documentation/application-integration-documentation.js +23 -0
  11. package/dist/esm/companion/application-documentation/application-integration-documentation.js.map +1 -1
  12. package/dist/esm/companion/application-documentation/application-organization-role-documentation.d.ts +30 -0
  13. package/dist/esm/companion/application-documentation/application-organization-role-documentation.d.ts.map +1 -1
  14. package/dist/esm/companion/application-documentation/application-organization-role-documentation.js +38 -0
  15. package/dist/esm/companion/application-documentation/application-organization-role-documentation.js.map +1 -1
  16. package/dist/esm/companion/application-documentation/technical-documentation-engine-content-bundle.d.ts +61 -1
  17. package/dist/esm/companion/application-documentation/technical-documentation-engine-content-bundle.d.ts.map +1 -1
  18. package/dist/esm/companion/application-documentation/technical-documentation-engine-content-bundle.js +255 -218
  19. package/dist/esm/companion/application-documentation/technical-documentation-engine-content-bundle.js.map +1 -1
  20. package/dist/esm/companion/application-documentation/technical-documentation-private-derivation.d.ts +2 -0
  21. package/dist/esm/companion/application-documentation/technical-documentation-private-derivation.d.ts.map +1 -1
  22. package/dist/esm/companion/application-documentation/technical-documentation-private-derivation.js +1 -0
  23. package/dist/esm/companion/application-documentation/technical-documentation-private-derivation.js.map +1 -1
  24. package/dist/esm/companion/application-documentation/technical-documentation-publication-policy.js +1 -1
  25. package/dist/esm/companion/application-documentation/technical-documentation-publication-policy.js.map +1 -1
  26. package/dist/esm/companion/index.d.ts +2 -1
  27. package/dist/esm/companion/index.d.ts.map +1 -1
  28. package/dist/esm/companion/index.js +2 -1
  29. package/dist/esm/companion/index.js.map +1 -1
  30. package/dist/esm/companion/manual-controller-route-projection.d.ts +112 -0
  31. package/dist/esm/companion/manual-controller-route-projection.d.ts.map +1 -0
  32. package/dist/esm/companion/manual-controller-route-projection.js +249 -0
  33. package/dist/esm/companion/manual-controller-route-projection.js.map +1 -0
  34. package/dist/esm/companion/openapi-generator.d.ts +16 -0
  35. package/dist/esm/companion/openapi-generator.d.ts.map +1 -1
  36. package/dist/esm/companion/openapi-generator.js +489 -26
  37. package/dist/esm/companion/openapi-generator.js.map +1 -1
  38. package/dist/esm/companion/operation-projection.schemas.d.ts +44 -0
  39. package/dist/esm/companion/operation-projection.schemas.d.ts.map +1 -1
  40. package/dist/esm/companion/operation-projection.schemas.js +37 -0
  41. package/dist/esm/companion/operation-projection.schemas.js.map +1 -1
  42. package/dist/esm/companion/rendering/technical-documentation-docusaurus-renderer.d.ts +7 -1
  43. package/dist/esm/companion/rendering/technical-documentation-docusaurus-renderer.d.ts.map +1 -1
  44. package/dist/esm/companion/rendering/technical-documentation-docusaurus-renderer.js +34 -18
  45. package/dist/esm/companion/rendering/technical-documentation-docusaurus-renderer.js.map +1 -1
  46. package/dist/esm/companion/rendering/technical-documentation-managed-tree-validator.d.ts.map +1 -1
  47. package/dist/esm/companion/rendering/technical-documentation-managed-tree-validator.js +8 -1
  48. package/dist/esm/companion/rendering/technical-documentation-managed-tree-validator.js.map +1 -1
  49. package/dist/esm/companion/rendering/technical-documentation-markdown-renderer.d.ts +0 -9
  50. package/dist/esm/companion/rendering/technical-documentation-markdown-renderer.d.ts.map +0 -1
  51. package/dist/esm/companion/rendering/technical-documentation-markdown-renderer.js +0 -111
  52. package/dist/esm/companion/rendering/technical-documentation-markdown-renderer.js.map +0 -1
  53. package/dist/esm/companion/rendering/technical-documentation-render-model.d.ts.map +1 -1
  54. package/dist/esm/companion/rendering/technical-documentation-render-model.js +30 -13
  55. package/dist/esm/companion/rendering/technical-documentation-render-model.js.map +1 -1
  56. package/dist/esm/companion/rendering/technical-documentation-search-index-renderer.d.ts +10 -0
  57. package/dist/esm/companion/rendering/technical-documentation-search-index-renderer.d.ts.map +1 -1
  58. package/dist/esm/companion/rendering/technical-documentation-search-index-renderer.js +10 -15
  59. package/dist/esm/companion/rendering/technical-documentation-search-index-renderer.js.map +1 -1
  60. package/dist/esm/companion/technical-documentation-capture-execution-port.d.ts +27 -1
  61. package/dist/esm/companion/technical-documentation-capture-execution-port.d.ts.map +1 -1
  62. package/dist/esm/companion/technical-documentation-capture-execution-port.js.map +1 -1
  63. package/dist/esm/companion/technical-documentation-diagram-definitions.d.ts +33 -0
  64. package/dist/esm/companion/technical-documentation-diagram-definitions.d.ts.map +1 -0
  65. package/dist/esm/companion/technical-documentation-diagram-definitions.js +54 -0
  66. package/dist/esm/companion/technical-documentation-diagram-definitions.js.map +1 -0
  67. package/dist/esm/companion/technical-documentation-diagram-materializer.d.ts +10 -18
  68. package/dist/esm/companion/technical-documentation-diagram-materializer.d.ts.map +1 -1
  69. package/dist/esm/companion/technical-documentation-diagram-materializer.js +9 -39
  70. package/dist/esm/companion/technical-documentation-diagram-materializer.js.map +1 -1
  71. package/dist/esm/config/wildo-tech-doc-config.schemas.d.ts +8 -4
  72. package/dist/esm/config/wildo-tech-doc-config.schemas.d.ts.map +1 -1
  73. package/dist/esm/config/wildo-tech-doc-config.schemas.js +8 -4
  74. package/dist/esm/config/wildo-tech-doc-config.schemas.js.map +1 -1
  75. package/dist/esm/content/application-consumer-documentation-content.techdoc.d.ts +42 -64
  76. package/dist/esm/content/application-consumer-documentation-content.techdoc.d.ts.map +1 -1
  77. package/dist/esm/content/application-consumer-documentation-content.techdoc.js +164 -925
  78. package/dist/esm/content/application-consumer-documentation-content.techdoc.js.map +1 -1
  79. package/dist/esm/runtime/DocsAuthContext.d.ts +16 -1
  80. package/dist/esm/runtime/DocsAuthContext.d.ts.map +1 -1
  81. package/dist/esm/runtime/DocsAuthContext.js +18 -2
  82. package/dist/esm/runtime/DocsAuthContext.js.map +1 -1
  83. package/dist/esm/runtime/frontend-provider-registry.techdoc.d.ts +35 -13
  84. package/dist/esm/runtime/frontend-provider-registry.techdoc.d.ts.map +1 -1
  85. package/dist/esm/runtime/frontend-provider-registry.techdoc.js +28 -19
  86. package/dist/esm/runtime/frontend-provider-registry.techdoc.js.map +1 -1
  87. package/dist/esm/runtime/index.d.ts +1 -0
  88. package/dist/esm/runtime/index.d.ts.map +1 -1
  89. package/dist/esm/runtime/index.js +1 -0
  90. package/dist/esm/runtime/index.js.map +1 -1
  91. package/dist/esm/runtime/use-docs-provider-sdks.d.ts +21 -0
  92. package/dist/esm/runtime/use-docs-provider-sdks.d.ts.map +1 -0
  93. package/dist/esm/runtime/use-docs-provider-sdks.js +49 -0
  94. package/dist/esm/runtime/use-docs-provider-sdks.js.map +1 -0
  95. package/dist/tsconfig.build.tsbuildinfo +1 -1
  96. package/package.json +6 -5
@@ -1 +1 @@
1
- {"version":3,"file":"application-consumer-documentation-content.techdoc.js","sourceRoot":"","sources":["../../../../src/content/application-consumer-documentation-content.techdoc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,sDAAsD,GAAG;IACpE;QACE,WAAW,EAAE,gBAAgB;QAC7B,OAAO,EAAE,sDAAsD;QAC/D,UAAU,EAAE;YACV,2DAA2D;YAC3D,oDAAoD;SACrD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sUAkCwT;KACnU;IACD;QACE,WAAW,EAAE,iCAAiC;QAC9C,OAAO,EAAE,6CAA6C;QACtD,UAAU,EAAE;YACV,kDAAkD;YAClD,wDAAwD;YACxD,oDAAoD;YACpD,oDAAoD;SACrD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wEAuE0D;KACrE;IACD;QACE,WAAW,EAAE,wCAAwC;QACrD,OAAO,EAAE,8CAA8C;QACvD,UAAU,EAAE;YACV,mDAAmD;YACnD,wDAAwD;YACxD,oDAAoD;SACrD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iEA+EmD;KAC9D;IACD;QACE,WAAW,EAAE,yCAAyC;QACtD,OAAO,EAAE,+CAA+C;QACxD,UAAU,EAAE;YACV,oDAAoD;YACpD,oDAAoD;SACrD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8EAwEgE;KAC3E;IACD;QACE,WAAW,EAAE,oDAAoD;QACjE,OAAO,EAAE,0DAA0D;QACnE,UAAU,EAAE;YACV,+DAA+D;YAC/D,wDAAwD;SACzD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yDAqG2C;KACtD;IACD;QACE,WAAW,EAAE,6CAA6C;QAC1D,OAAO,EAAE,mDAAmD;QAC5D,UAAU,EAAE,CAAC,wDAAwD,CAAC;QACtE,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qEAqEuD;KAClE;IACD;QACE,WAAW,EAAE,uCAAuC;QACpD,OAAO,EAAE,6CAA6C;QACtD,UAAU,EAAE;YACV,kDAAkD;YAClD,4CAA4C;SAC7C;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aA6ID;KACV;IACD;QACE,WAAW,EAAE,sCAAsC;QACnD,OAAO,EAAE,4CAA4C;QACrD,UAAU,EAAE;YACV,iDAAiD;YACjD,4CAA4C;SAC7C;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+EA+NiE;KAC5E;IACD;QACE,WAAW,EAAE,iDAAiD;QAC9D,OAAO,EAAE,uDAAuD;QAChE,UAAU,EAAE;YACV,4DAA4D;YAC5D,4CAA4C;SAC7C;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uEAuJyD;KACpE;IACD;QACE,WAAW,EAAE,yCAAyC;QACtD,OAAO,EAAE,+CAA+C;QACxD,UAAU,EAAE;YACV,oDAAoD;YACpD,4CAA4C;SAC7C;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qDAyJuC;KAClD;IACD;QACE,WAAW,EAAE,iCAAiC;QAC9C,OAAO,EAAE,uCAAuC;QAChD,UAAU,EAAE;YACV,4CAA4C;YAC5C,sCAAsC;SACvC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uEAgFyD;KACpE;IACD;QACE,WAAW,EAAE,kDAAkD;QAC/D,OAAO,EAAE,wDAAwD;QACjE,UAAU,EAAE;YACV,6DAA6D;YAC7D,sCAAsC;SACvC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mEA2HqD;KAChE;IACD;QACE,WAAW,EAAE,2CAA2C;QACxD,OAAO,EAAE,iDAAiD;QAC1D,UAAU,EAAE;YACV,sDAAsD;YACtD,sCAAsC;SACvC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6CAwI+B;KAC1C;IACD;QACE,WAAW,EAAE,8CAA8C;QAC3D,OAAO,EAAE,oDAAoD;QAC7D,UAAU,EAAE;YACV,yDAAyD;YACzD,sCAAsC;SACvC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uCAuFyB;KACpC;IACD;QACE,WAAW,EAAE,uCAAuC;QACpD,OAAO,EAAE,6CAA6C;QACtD,UAAU,EAAE;YACV,kDAAkD;YAClD,2CAA2C;SAC5C;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8DA6JgD;KAC3D;IACD;QACE,WAAW,EAAE,8CAA8C;QAC3D,OAAO,EAAE,oDAAoD;QAC7D,UAAU,EAAE;YACV,yDAAyD;YACzD,2CAA2C;SAC5C;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uCAsIyB;KACpC;IACD;QACE,WAAW,EAAE,yDAAyD;QACtE,OAAO,EAAE,+DAA+D;QACxE,UAAU,EAAE;YACV,oEAAoE;YACpE,2CAA2C;SAC5C;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2EA0I6D;KACxE;IACD;QACE,WAAW,EAAE,iDAAiD;QAC9D,OAAO,EAAE,uDAAuD;QAChE,UAAU,EAAE;YACV,4DAA4D;YAC5D,2CAA2C;SAC5C;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iCA8HmB;KAC9B;IACD;QACE,WAAW,EAAE,wBAAwB;QACrC,OAAO,EAAE,kDAAkD;QAC3D,UAAU,EAAE;YACV,uDAAuD;SACxD;QACL,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iCAgFuB;KAC9B;IACD;QACE,WAAW,EAAE,8CAA8C;QAC3D,OAAO,EAAE,oDAAoD;QAC7D,UAAU,EAAE;YACV,yDAAyD;YACzD,6DAA6D;SAC9D;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yCAwD2B;KACtC;IACD;QACE,WAAW,EAAE,gDAAgD;QAC7D,OAAO,EAAE,sDAAsD;QAC/D,UAAU,EAAE;YACV,2DAA2D;SAC5D;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mDA4HqC;KAChD;IACD;QACE,WAAW,EAAE,8CAA8C;QAC3D,OAAO,EAAE,iDAAiD;QAC1D,UAAU,EAAE;YACV,sDAAsD;YACtD,wDAAwD;YACxD,gDAAgD;YAChD,6DAA6D;SAC9D;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4CAwH8B;KACzC;IACD;QACE,WAAW,EAAE,2CAA2C;QACxD,OAAO,EAAE,iDAAiD;QAC1D,UAAU,EAAE;YACV,sDAAsD;SACvD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kCAuJoB;KAC/B;IACD;QACE,WAAW,EAAE,kDAAkD;QAC/D,OAAO,EAAE,wDAAwD;QACjE,UAAU,EAAE;YACV,6DAA6D;YAC7D,wDAAwD;YACxD,+DAA+D;YAC/D,yCAAyC;SAC1C;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yBAiEW;KACtB;IACD;QACE,WAAW,EAAE,2DAA2D;QACxE,OAAO,EAAE,iEAAiE;QAC1E,UAAU,EAAE,CAAC,sEAAsE,CAAC;QACpF,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+DA2EiD;KAC5D;IACD;QACE,WAAW,EAAE,wDAAwD;QACrE,OAAO,EAAE,8DAA8D;QACvE,UAAU,EAAE;YACV,mEAAmE;YACnE,+DAA+D;SAChE;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6CAwE+B;KAC1C;IACD;QACE,WAAW,EAAE,mDAAmD;QAChE,OAAO,EAAE,yDAAyD;QAClE,UAAU,EAAE,CAAC,8DAA8D,CAAC;QAC5E,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mDAuDqC;KAChD;IACD;QACE,WAAW,EAAE,+CAA+C;QAC5D,OAAO,EAAE,qDAAqD;QAC9D,UAAU,EAAE;YACV,0DAA0D;SAC3D;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2DAkH6C;KACxD;IACD;QACE,WAAW,EAAE,gDAAgD;QAC7D,OAAO,EAAE,sDAAsD;QAC/D,UAAU,EAAE;YACV,2DAA2D;SAC5D;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4CA2F8B;KACzC;IACD;QACE,WAAW,EAAE,iDAAiD;QAC9D,OAAO,EAAE,uDAAuD;QAChE,UAAU,EAAE,CAAC,4DAA4D,CAAC;QAC1E,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2CA4E6B;KACxC;IACD;QACE,WAAW,EAAE,0CAA0C;QACvD,OAAO,EAAE,mCAAmC;QAC5C,UAAU,EAAE;YACV,wCAAwC;YACxC,qDAAqD;SACtD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oCAoFsB;KACjC;IACD;QACE,WAAW,EAAE,mDAAmD;QAChE,OAAO,EAAE,yDAAyD;QAClE,UAAU,EAAE;YACV,8DAA8D;YAC9D,qDAAqD;SACtD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wEA6K0D;KACrE;IACD;QACE,WAAW,EAAE,uCAAuC;QACpD,OAAO,EAAE,6CAA6C;QACtD,UAAU,EAAE;YACV,kDAAkD;YAClD,qDAAqD;SACtD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAuGJ;KACP;IACD;QACE,WAAW,EAAE,6CAA6C;QAC1D,OAAO,EAAE,mDAAmD;QAC5D,UAAU,EAAE,CAAC,wDAAwD,CAAC;QACtE,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iFAuHmE;KAC9E;IACD;QACE,WAAW,EAAE,kCAAkC;QAC/C,OAAO,EAAE,wCAAwC;QACjD,UAAU,EAAE,CAAC,6CAA6C,CAAC;QAC3D,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wEAqG0D;KACrE;IACD;QACE,WAAW,EAAE,uDAAuD;QACpE,OAAO,EAAE,6DAA6D;QACtE,UAAU,EAAE,CAAC,kEAAkE,CAAC;QAChF,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mDAsHqC;KAChD;IACD;QACE,WAAW,EAAE,mDAAmD;QAChE,OAAO,EAAE,yDAAyD;QAClE,UAAU,EAAE,CAAC,8DAA8D,CAAC;QAC5E,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA2EU;KACrB;IACD;QACE,WAAW,EAAE,mDAAmD;QAChE,OAAO,EAAE,yDAAyD;QAClE,UAAU,EAAE,CAAC,8DAA8D,CAAC;QAC5E,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mDAuDqC;KAChD;IACD;QACE,WAAW,EAAE,sDAAsD;QACnE,OAAO,EAAE,4DAA4D;QACrE,UAAU,EAAE,CAAC,iEAAiE,CAAC;QAC/E,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA0DO;KAClB;IACD;QACE,WAAW,EAAE,4CAA4C;QACzD,OAAO,EAAE,6CAA6C;QACtD,UAAU,EAAE,CAAC,kDAAkD,CAAC;QAChE,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4DAgF8C;KACzD;IACD;QACE,WAAW,EAAE,yCAAyC;QACtD,OAAO,EAAE,sDAAsD;QAC/D,UAAU,EAAE;YACV,2DAA2D;YAC3D,+CAA+C;SAChD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6CAyG+B;KAC1C;IACD;QACE,WAAW,EAAE,6CAA6C;QAC1D,OAAO,EAAE,mEAAmE;QAC5E,UAAU,EAAE,CAAC,wEAAwE,CAAC;QACtF,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mEA8EqD;KAChE;IACD;QACE,WAAW,EAAE,4CAA4C;QACzD,OAAO,EAAE,mDAAmD;QAC5D,UAAU,EAAE,CAAC,wDAAwD,CAAC;QACtE,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gJAqGkI;KAC7I;IACD;QACE,WAAW,EAAE,sCAAsC;QACnD,OAAO,EAAE,oDAAoD;QAC7D,UAAU,EAAE;YACV,yDAAyD;YACzD,+CAA+C;SAChD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+BA0LiB;KAC5B;IACD;QACE,WAAW,EAAE,mCAAmC;QAChD,OAAO,EAAE,0CAA0C;QACnD,UAAU,EAAE;YACV,+CAA+C;YAC/C,+CAA+C;SAChD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oEAgHsD;KACjE;IACD;QACE,WAAW,EAAE,+CAA+C;QAC5D,OAAO,EAAE,sDAAsD;QAC/D,UAAU,EAAE;YACV,2DAA2D;YAC3D,+CAA+C;SAChD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wCA+F0B;KACrC;IACD;QACE,WAAW,EAAE,oCAAoC;QACjD,OAAO,EAAE,2CAA2C;QACpD,UAAU,EAAE;YACV,gDAAgD;YAChD,+CAA+C;SAChD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yDAsH2C;KACtD;IACD;QACE,WAAW,EAAE,oCAAoC;QACjD,OAAO,EAAE,qEAAqE;QAC9E,UAAU,EAAE;YACV,0EAA0E;YAC1E,+CAA+C;SAChD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wEA0F0D;KACrE;IACD;QACE,WAAW,EAAE,wCAAwC;QACrD,OAAO,EAAE,gEAAgE;QACzE,UAAU,EAAE,CAAC,qEAAqE,CAAC;QACnF,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4EA4F8D;KACzE;IACD;QACE,WAAW,EAAE,sCAAsC;QACnD,OAAO,EAAE,sCAAsC;QAC/C,UAAU,EAAE;YACV,2CAA2C;YAC3C,wCAAwC;SACzC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAuEa;KACxB;IACD;QACE,WAAW,EAAE,+CAA+C;QAC5D,OAAO,EAAE,kEAAkE;QAC3E,UAAU,EAAE;YACV,uEAAuE;YACvE,wCAAwC;SACzC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oDAmJsC;KACjD;IACD;QACE,WAAW,EAAE,iDAAiD;QAC9D,OAAO,EAAE,yDAAyD;QAClE,UAAU,EAAE;YACV,8DAA8D;SAC/D;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAsGA;KACX;IACD;QACE,WAAW,EAAE,yDAAyD;QACtE,OAAO,EAAE,iEAAiE;QAC1E,UAAU,EAAE;YACV,sEAAsE;YACtE,wCAAwC;SACzC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iCAwHmB;KAC9B;IACD;QACE,WAAW,EAAE,8CAA8C;QAC3D,OAAO,EAAE,wDAAwD;QACjE,UAAU,EAAE,CAAC,6DAA6D,CAAC;QAC3E,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wEAqD0D;KACrE;IACD;QACE,WAAW,EAAE,oDAAoD;QACjE,OAAO,EAAE,2DAA2D;QACpE,UAAU,EAAE;YACV,gEAAgE;YAChE,wCAAwC;SACzC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wEAyF0D;KACrE;IACD;QACE,WAAW,EAAE,4CAA4C;QACzD,OAAO,EAAE,uDAAuD;QAChE,UAAU,EAAE;YACV,4DAA4D;YAC5D,wCAAwC;SACzC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4EA0F8D;KACzE;IACD;QACE,WAAW,EAAE,+CAA+C;QAC5D,OAAO,EAAE,2DAA2D;QACpE,UAAU,EAAE;YACV,gEAAgE;YAChE,wCAAwC;SACzC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+DAoFiD;KAC5D;IACD;QACE,WAAW,EAAE,2CAA2C;QACxD,OAAO,EAAE,0DAA0D;QACnE,UAAU,EAAE;YACV,+DAA+D;SAChE;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qEA2EuD;KAClE;IACD;QACE,WAAW,EAAE,iBAAiB;QAC9B,OAAO,EAAE,2CAA2C;QACpD,UAAU,EAAE,CAAC,gDAAgD,CAAC;QAC9D,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yNA8E2M;KACtN;IACD;QACE,WAAW,EAAE,sCAAsC;QACnD,OAAO,EAAE,mDAAmD;QAC5D,UAAU,EAAE,CAAC,wDAAwD,CAAC;QACtE,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uDAoDyC;KACpD;IACD;QACE,WAAW,EAAE,gCAAgC;QAC7C,OAAO,EAAE,0CAA0C;QACnD,UAAU,EAAE;YACV,+CAA+C;YAC/C,sCAAsC;SACvC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8CAgLgC;KAC3C;IACD;QACE,WAAW,EAAE,mCAAmC;QAChD,OAAO,EAAE,6CAA6C;QACtD,UAAU,EAAE;YACV,kDAAkD;YAClD,sCAAsC;SACvC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mDA+JqC;KAChD;IACD;QACE,WAAW,EAAE,iCAAiC;QAC9C,OAAO,EAAE,2CAA2C;QACpD,UAAU,EAAE;YACV,gDAAgD;YAChD,sCAAsC;SACvC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uDA4JyC;KACpD;IACD;QACE,WAAW,EAAE,iCAAiC;QAC9C,OAAO,EAAE,8CAA8C;QACvD,UAAU,EAAE;YACV,mDAAmD;YACnD,oDAAoD;SACrD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBAuDS;KACpB;IACD;QACE,WAAW,EAAE,iCAAiC;QAC9C,OAAO,EAAE,6CAA6C;QACtD,UAAU,EAAE;YACV,kDAAkD;YAClD,oDAAoD;SACrD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sCAoIwB;KACnC;IACD;QACE,WAAW,EAAE,gCAAgC;QAC7C,OAAO,EAAE,4CAA4C;QACrD,UAAU,EAAE;YACV,iDAAiD;YACjD,oDAAoD;SACrD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4DAkI8C;KACzD;IACD;QACE,WAAW,EAAE,sCAAsC;QACnD,OAAO,EAAE,kDAAkD;QAC3D,UAAU,EAAE;YACV,uDAAuD;YACvD,oDAAoD;SACrD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAyHJ;KACP;IACD;QACE,WAAW,EAAE,wBAAwB;QACrC,OAAO,EAAE,qDAAqD;QAC9D,UAAU,EAAE,CAAC,0DAA0D,CAAC;QACxE,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gEAuHkD;KAC7D;IACD;QACE,WAAW,EAAE,6CAA6C;QAC1D,OAAO,EAAE,4CAA4C;QACrD,UAAU,EAAE;YACV,iDAAiD;YACjD,oDAAoD;YACpD,sCAAsC;SACvC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8DAgLgD;KAC3D;IACD;QACE,WAAW,EAAE,0BAA0B;QACvC,OAAO,EAAE,8CAA8C;QACvD,UAAU,EAAE;YACV,mDAAmD;SACpD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;2KA0B6J;KACxK;IACD;QACE,WAAW,EAAE,kCAAkC;QAC/C,OAAO,EAAE,mDAAmD;QAC5D,UAAU,EAAE;YACV,wDAAwD;YACxD,oDAAoD;YACpD,sCAAsC;YACtC,uCAAuC;SACxC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wUAyF0T;KACrU;IACD;QACE,WAAW,EAAE,mCAAmC;QAChD,OAAO,EAAE,+CAA+C;QACxD,UAAU,EAAE;YACV,oDAAoD;YACpD,oDAAoD;YACpD,sCAAsC;SACvC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0VA0E4U;KACvV;IACD;QACE,WAAW,EAAE,uCAAuC;QACpD,OAAO,EAAE,wDAAwD;QACjE,UAAU,EAAE;YACV,6DAA6D;YAC7D,uCAAuC;SACxC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mSAmEqR;KAChS;IACD;QACE,WAAW,EAAE,0CAA0C;QACvD,OAAO,EAAE,8DAA8D;QACvE,UAAU,EAAE;YACV,mEAAmE;YACnE,uCAAuC;SACxC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2WAyD6V;KACxW;IACD;QACE,WAAW,EAAE,mCAAmC;QAChD,OAAO,EAAE,uDAAuD;QAChE,UAAU,EAAE;YACV,4DAA4D;YAC5D,sCAAsC;YACtC,uCAAuC;SACxC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iOA4DmN;KAC9N;IACD;QACE,WAAW,EAAE,0BAA0B;QACvC,OAAO,EAAE,uCAAuC;QAChD,UAAU,EAAE;YACV,4CAA4C;YAC5C,qDAAqD;YACrD,wCAAwC;SACzC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yIAmC2H;KACtI;IACD;QACE,WAAW,EAAE,6CAA6C;QAC1D,OAAO,EAAE,kEAAkE;QAC3E,UAAU,EAAE;YACV,uEAAuE;YACvE,wCAAwC;SACzC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0TA+C4S;KACvT;IACD;QACE,WAAW,EAAE,0CAA0C;QACvD,OAAO,EAAE,sDAAsD;QAC/D,UAAU,EAAE;YACV,2DAA2D;YAC3D,wCAAwC;SACzC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;idAsDmc;KAC9c;IACD;QACE,WAAW,EAAE,6CAA6C;QAC1D,OAAO,EAAE,yDAAyD;QAClE,UAAU,EAAE;YACV,8DAA8D;YAC9D,wCAAwC;SACzC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iUAqDmT;KAC9T;IACD;QACE,WAAW,EAAE,uCAAuC;QACpD,OAAO,EAAE,8DAA8D;QACvE,UAAU,EAAE;YACV,mEAAmE;YACnE,wCAAwC;SACzC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4PAyC8O;KACzP;IACD;QACE,WAAW,EAAE,qBAAqB;QAClC,OAAO,EAAE,+CAA+C;QACxD,UAAU,EAAE;YACV,oDAAoD;YACpD,oDAAoD;YACpD,qDAAqD;SACtD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAkQa;KACxB;IACD;QACE,WAAW,EAAE,qBAAqB;QAClC,OAAO,EAAE,+CAA+C;QACxD,UAAU,EAAE;YACV,oDAAoD;YACpD,oDAAoD;SACrD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+DAgTiD;KAC5D;CACO,CAAC","sourcesContent":["/**\n * Canonical engine-owned application-consumer documentation fragments.\n *\n * This neutral reusable-content module is deliberately data-only: no imports,\n * calls, environment reads, Wildo application-authoring guidance or executable\n * MDX. Companion-side projectors validate and digest these values before any\n * generated application may consume them.\n *\n * The fragments describe customer-facing product domains and integration\n * journeys, not a generic “technical guides” catalogue. Application-domain\n * use cases are deliberately absent until the app-creator flow owns their\n * authoring and acceptance.\n */\nexport const APPLICATION_CONSUMER_DOCUMENTATION_AUTHORED_CONTENT_V1 = [\n {\n managedPath: 'get-started.md',\n unitRef: 'technical-documentation:unit/application-orientation',\n sourceRefs: [\n 'saas-technical-doc:engine-content/application-orientation',\n 'source:companion-projection:application-connection',\n ],\n 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.`,\n },\n {\n managedPath: 'access-and-identity/overview.md',\n unitRef: 'technical-documentation:unit/authentication',\n sourceRefs: [\n 'saas-technical-doc:engine-content/authentication',\n 'source:companion-projection:application-authentication',\n 'source:companion-projection:application-connection',\n 'source:consumer-fact:access-authentication-methods',\n ],\n 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.`,\n },\n {\n managedPath: 'access-and-identity/sign-in-and-mfa.md',\n unitRef: 'technical-documentation:unit/sign-in-and-mfa',\n sourceRefs: [\n 'saas-technical-doc:engine-content/sign-in-and-mfa',\n 'source:companion-projection:application-authentication',\n 'source:consumer-fact:access-authentication-methods',\n ],\n 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.`,\n },\n {\n managedPath: 'access-and-identity/complete-sign-in.md',\n unitRef: 'technical-documentation:unit/complete-sign-in',\n sourceRefs: [\n 'saas-technical-doc:engine-content/complete-sign-in',\n 'source:consumer-fact:access-authentication-methods',\n ],\n 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.`,\n },\n {\n managedPath: 'access-and-identity/mfa-enrollment-and-recovery.md',\n unitRef: 'technical-documentation:unit/mfa-enrollment-and-recovery',\n sourceRefs: [\n 'saas-technical-doc:engine-content/mfa-enrollment-and-recovery',\n 'source:companion-projection:application-authentication',\n ],\n 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.`,\n },\n {\n managedPath: 'access-and-identity/sign-in-troubleshoot.md',\n unitRef: 'technical-documentation:unit/sign-in-troubleshoot',\n sourceRefs: ['saas-technical-doc:engine-content/sign-in-troubleshoot'],\n 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.`,\n },\n {\n managedPath: 'access-and-identity/single-sign-on.md',\n unitRef: 'technical-documentation:unit/single-sign-on',\n sourceRefs: [\n 'saas-technical-doc:engine-content/single-sign-on',\n 'source:consumer-fact:access-single-sign-on',\n ],\n markdown: `# Single sign-on\n\nSingle sign-on lets people authenticate through an organization's identity\nprovider. It changes **how identity is proven**; it does not create membership,\nchoose roles or remove access when somebody leaves. Use [User\nadministration](/user-administration) or SCIM for those lifecycle decisions.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Identify the organization, identity-provider owner, application owner and an independent administrator recovery method | People enter through the intended provider, resolve to the intended organization and receive only their approved application access |\n\n## Know what SSO owns\n\n| Question | Owned by SSO? | Where to manage it |\n| --- | --- | --- |\n| How does the person prove identity? | **Yes** | Identity-provider policy and this connection's trust settings |\n| May a new provider identity create an application user? | **Connection-dependent** | Just-in-time creation and identity-mapping controls |\n| Is the person a member of this organization? | **No** | Manual user administration or SCIM lifecycle policy |\n| Which application operations may the person perform? | **No** | Organization roles and the exact operation contract |\n| Does leaving the identity provider remove application access? | **Not by SSO alone** | Manual suspension/removal or SCIM deprovisioning |\n\nThis separation matters during both setup and incidents. A provider can accept a\nperson while the application correctly refuses an inactive membership, and an\nactive application membership can remain after provider access is removed if no\nuser-lifecycle process updates it.\n\n~~~mermaid\nsequenceDiagram\n accTitle: Sign in through an organization identity provider\n accDescr: A person starts at the application, authenticates through the configured identity provider, and returns with a response the application validates before starting a session.\n participant Person\n participant App as Application\n participant IdP as Identity provider\n Person->>App: Start organization sign-in\n App->>IdP: Redirect using configured connection\n IdP->>Person: Authenticate and satisfy provider policy\n IdP->>App: Return signed response\n App->>App: Validate trust and organization context\n App-->>Person: Start application session\n~~~\n\nThe result is not merely a completed redirect. The response must come from the\nintended provider, validate for this environment and map to the intended person\nand organization.\n\n## Choose a connection protocol with the provider owner\n\nThe application supports the connection protocols shown below. Use the protocol\nthe organization's provider can operate and monitor consistently; do not choose\none because its configuration form looks shorter.\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#markdown}}\n\n- **OpenID Connect** commonly uses provider discovery, an issuer, a client\n identity, a protected client secret and signed tokens. The application must\n validate the response for the exact issuer, audience and environment.\n- **SAML** commonly uses provider and application entity identifiers, sign-in\n destinations and signing certificates. The application must validate the\n signature, audience, destination and timing of the assertion.\n\nBoth protocols still require a stable person mapping, an organization\nmembership decision and an access test after authentication.\n\n~~~mermaid\nflowchart TD\n accTitle: Choose the protocol the organization can operate safely\n accDescr: The organization first checks which protocols the application and provider support, then prefers OpenID Connect for a new compatible integration, retains SAML for an established enterprise federation, and verifies the same identity, membership and recovery outcomes in either case.\n start[\"Application and provider owners meet\"] --> supported{\"Both sides support OIDC?\"}\n supported -->|\"Yes\"| oidc[\"Prefer OIDC for a new connection\"]\n supported -->|\"No\"| samlSupported{\"Both sides support SAML 2.0?\"}\n samlSupported -->|\"Yes\"| saml[\"Configure SAML federation\"]\n samlSupported -->|\"No\"| stop[\"No supported SSO connection\"]\n oidc --> proof[\"Prove identity, organization, role and recovery\"]\n saml --> proof\n~~~\n\nThe choice is operational, not cosmetic. OIDC exchanges compact signed tokens\nand normally publishes provider metadata. SAML exchanges signed XML assertions\nand commonly uses federation metadata plus signing certificates. **Do not\ntranslate values between the protocols by name alone**: an OIDC issuer is not a\nSAML entity ID, an OIDC redirect URI is not a SAML audience, and a signing-key\nset is not interchangeable with a SAML certificate configuration.\n\n| Decision | Prefer OpenID Connect when… | Prefer SAML when… |\n| --- | --- | --- |\n| Existing provider integration | The provider operates a maintained OIDC application registration | The organization already operates a reviewed SAML enterprise application |\n| Trust renewal | Issuer metadata and signing keys can be monitored through the provider | Certificate lifecycle and federation metadata already have named owners |\n| Identity data | Stable OIDC claims can provide the required person attributes | Existing SAML attribute statements already carry the required attributes |\n| Provider-started access | Application-started authorization is acceptable | A deliberately approved IdP-started journey is required and tested |\n| New implementation | Both sides support authorization code with PKCE and strict issuer/audience validation | OIDC is unavailable or the provider's supported enterprise contract is SAML |\n\n## Understand the standards before changing trust\n\n- [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html)\n defines the identity layer, authorization response and ID-token validation.\n- [OpenID Connect Discovery 1.0](https://openid.net/specs/openid-connect-discovery-1_0.html)\n defines provider metadata such as issuer, endpoints and signing-key location.\n- [OAuth 2.0 authorization-server metadata (RFC 8414)](https://www.rfc-editor.org/rfc/rfc8414)\n describes discovery metadata used by OAuth/OIDC deployments.\n- [Proof Key for Code Exchange (RFC 7636)](https://www.rfc-editor.org/rfc/rfc7636)\n defines the code-verifier protection used by the default OIDC journey.\n- [OASIS SAML 2.0 technical overview](https://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-tech-overview-2.0.html)\n explains SAML roles, assertions and the browser SSO profiles.\n- [OASIS SAML 2.0 metadata](https://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf)\n defines the metadata exchanged between federation parties.\n\nThese documents define the protocol. The current application's displayed\nconnection values remain the authority for its URLs, identifiers and enabled\nfeatures.\n\n## Start with your provider's maintained instructions\n\n| Provider | OIDC starting point | SAML starting point |\n| --- | --- | --- |\n| Microsoft Entra ID | [Configure OIDC SSO for gallery and custom applications](https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/add-application-portal-setup-oidc-sso) | [Enable SAML SSO for an enterprise application](https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/add-application-portal-setup-sso) |\n| Okta | [Create an OIDC app integration](https://help.okta.com/en-us/content/topics/apps/apps_app_integration_wizard_oidc.htm) | [Create a SAML app integration](https://help.okta.com/en-us/content/topics/apps/apps_app_integration_wizard_saml.htm) |\n| Google Workspace or Cloud Identity | [Google OpenID Connect reference](https://developers.google.com/identity/openid-connect/openid-connect) | [Set up a custom SAML application](https://support.google.com/a/answer/6087519) |\n\nProvider documentation explains the provider side. Continue with the\napplication configuration guide to map those provider values to this\nenvironment's exact connection fields.\n\n## Follow the SSO journey\n\n| Your next task | Start here | Successful result |\n| --- | --- | --- |\n| Establish a new trust connection | [Configure a single sign-on connection](/access-and-identity/sso-configure) | The application and provider agree on protocol, identity, destinations and verification settings |\n| Introduce SSO safely | [Roll out SSO and keep a recovery path](/access-and-identity/sso-rollout-and-recovery) | A pilot signs in correctly and administrators retain an independent recovery method |\n| Investigate a failure | [Troubleshoot single sign-on](/access-and-identity/sso-troubleshoot) | The failing provider, trust, mapping, membership or role decision is identified without weakening validation |\n\nAn enabled connection can be used; a default connection may be selected\nautomatically by the sign-in experience. Do not make a connection default until\nits complete return journey and organization mapping have been verified.\n\n## Operate SSO as a shared service\n\nRecord owners for the provider and application configuration, the independent\nrecovery method, last controlled test, certificate or client-secret renewal\ndate, and the manual/SCIM process that removes organization access. Review trust\nand mapping changes as security changes. Keep passwords, client secrets, private\nkeys, complete assertions and session cookies out of ordinary tickets and\nscreenshots.`,\n },\n {\n managedPath: 'access-and-identity/sso-configure.md',\n unitRef: 'technical-documentation:unit/sso-configure',\n sourceRefs: [\n 'saas-technical-doc:engine-content/sso-configure',\n 'source:consumer-fact:access-single-sign-on',\n ],\n markdown: `# Configure a single sign-on connection\n\nCreate one connection for one organization and environment. This task is for an\norganization administrator working with the identity administrator who controls\nthe provider tenant.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Have an independent administrator recovery method, provider administration access, the current application's connection values and a controlled test identity | The application and provider identify each other correctly and a test response validates for the intended organization |\n\n~~~mermaid\nflowchart TD\n accTitle: Configure one single sign-on trust boundary\n accDescr: The application and identity-provider owners choose one protocol, exchange environment-specific identities and destinations, configure validation and identity mapping, test while the connection is not default, and enable it only after identity, organization and access checks pass.\n owners[\"Confirm owners and independent recovery\"] --> protocol[\"Choose OpenID Connect or SAML\"]\n protocol --> trust[\"Exchange identities, destinations and verification material\"]\n trust --> mapping[\"Define person, domain and role mapping\"]\n mapping --> controlled[\"Test one controlled identity\"]\n controlled --> access[\"Verify identity, organization, allowed action and refusal\"]\n access --> enable[\"Enable without making default\"]\n~~~\n\nKeep the connection isolated to one organization and environment. Production\nand non-production values may have similar labels but remain different trust\nboundaries.\n\n## Choose the protocol and connection controls\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#markdown}}\n\nGive the connection a display name that identifies the organization and\nenvironment. Keep it disabled while exchanging trust configuration when the\nadministration surface permits that sequence. Do not mark it as default yet.\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#connectionConfigurationMarkdown}}\n\n> **Current limitation:** keep \\`bypassAppMFA\\` off. The configuration field is\n> present, but the current authentication runtime does not use it to decide\n> whether the application requests another factor. Prove the actual sign-in\n> journey with a controlled account; do not use this field as audit evidence.\n\n> **SSO role mapping is an access grant.** Test every mapped value, keep the\n> fallback role non-administrative, and verify an expected refusal. A provider\n> group name should never become broad application authority merely because it\n> was previously used for a different system.\n\n## Exchange the trust configuration\n\nDepending on the selected protocol, the two administrators exchange the\nnon-secret identifiers and destinations needed to identify the application and\nprovider, plus the protected verification or client material required by that\nprotocol. Use only values displayed for the current environment.\n\nCheck these meanings before saving:\n\n- **Provider identity** names the provider tenant this connection trusts.\n- **Application identity or audience** tells the provider which application the\n response is intended for.\n- **Sign-in and return destinations** must belong to the matching environments.\n- **Identity mapping** must use a stable identity value rather than a display\n name that can change or collide.\n- **Verification settings** decide which signed responses the application will\n trust and how timing is evaluated.\n\n~~~mermaid\nflowchart LR\n accTitle: Map provider values to one application connection\n accDescr: The application publishes its callback or assertion-consumer destination and identity. The provider publishes its issuer or entity identity, endpoints and verification material. Both owners configure stable identity claims, and the application alone maps those claims to membership and least-privilege roles.\n app[\"Application environment\"] -->|\"Callback or ACS destination; application identity\"| provider[\"Identity provider tenant\"]\n provider -->|\"Issuer or entity ID; endpoints; signing material\"| app\n provider --> claims[\"Stable identity and optional role/group claims\"]\n claims --> mapping[\"Application claim and access mapping\"]\n mapping --> membership[\"Person + organization membership + roles\"]\n~~~\n\nThe arrows show two separate exchanges. Protocol trust lets the application\naccept a response from the provider. Claim and access mapping decides which\nperson and organization relationship that response may establish. Review both;\na valid signature does not make an unsafe group-to-admin mapping acceptable.\n\n### For an OpenID Connect connection\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#oidcConfigurationMarkdown}}\n\nPrefer the provider's maintained discovery information when the administration\nsurface supports it. Confirm the issuer and discovered authorization, token and\nsigning-key locations all belong to the same provider environment. Register the\nexact application return destination at the provider. Protect the client secret\nas write-only credential material, retain its renewal owner, and keep issuer and\naudience validation enabled. Use the strong proof method offered for the\nauthorization-code journey rather than weakening it to accommodate an old\nclient.\n\nChoose one endpoint mode deliberately:\n\n1. **Discovery** — supply the provider issuer or discovery URL. The sign-in\n runtime retrieves the current metadata and uses its issuer, authorization,\n token, user-info, signing-key and logout locations when published.\n2. **Provider template** — choose a maintained provider contract and supply its\n required tenant substitutions. Verify every resolved URL before enabling.\n3. **Manual** — supply the authorization and token endpoints, plus issuer,\n user-info and signing-key locations where required. Use this only when the\n provider cannot publish usable metadata.\n\n> The administrative **Discover endpoints** and **Test connection** operations\n> currently return \\`supported: false\\` for OIDC and perform no provider\n> handshake. This does not disable discovery-mode sign-in; it means the admin\n> diagnostic action cannot prove that connection. Use a controlled end-to-end\n> sign-in and provider logs as the positive test.\n\n### For a SAML connection\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#samlConfigurationMarkdown}}\n\nConfirm the provider entity identifier, application audience, sign-in\ndestination and assertion return destination as a single environment-specific\nset. Load the current provider signing certificate through the protected\nadministration surface and plan renewal before it expires. Keep signed-assertion\nvalidation enabled. Choose a stable subject/NameID and explicit attribute\nmapping; do not use a mutable display name as the person's identity.\n\nThe administrative **Discover endpoints** operation can retrieve SAML metadata\nand return the provider entity ID, sign-in/logout URLs, certificates and NameID\nformat for review. It does **not** save those values. After saving the\nconnection, **Test connection** checks the configured entity ID, endpoint\nreachability, certificate validity and generated service-provider metadata. A\npass is useful preflight evidence, but only a real application-started sign-in\nproves the browser, provider policy, response validation and identity mapping.\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#diagnosticsMarkdown}}\n\n## Configure a common identity provider\n\nThe provider changes the names and screens, not the application trust model.\nAlways copy the application values from the **same environment** you are\nconfiguring; the examples below deliberately contain no reusable callback URL,\nentity ID, client ID or secret.\n\n| Application meaning | Microsoft Entra ID | Okta | Google Workspace / Cloud Identity |\n| --- | --- | --- | --- |\n| OIDC application identity | App registration **Application (client) ID** | OIDC app **Client ID** | OAuth client **Client ID** |\n| OIDC return destination | App registration **Redirect URI** | **Sign-in redirect URI** | OAuth client **Authorized redirect URI** |\n| OIDC provider identity | Tenant-specific issuer/discovery document | Okta authorization-server issuer | Google issuer/discovery document |\n| SAML application identity | **Identifier (Entity ID)** | **Audience URI (SP Entity ID)** | **Entity ID** |\n| SAML return destination | **Reply URL (ACS URL)** | **Single sign-on URL** | **ACS URL** |\n| SAML provider identity | Microsoft Entra Identifier | Identity Provider Issuer | Google Entity ID |\n| SAML verification material | SAML signing certificate / federation metadata | Signing certificate / IdP metadata | Certificate / IdP metadata |\n\n### Microsoft Entra ID\n\nFor OIDC, create or select the application registration, register the exact web\nredirect URI supplied by this application environment, use the tenant-specific\nissuer, and create a client credential with a named owner and expiry. Keep the\nprovider assignment limited to the pilot population. Microsoft distinguishes\nthe app registration (the application definition) from its enterprise\napplication/service-principal instance; record both identities during support.\n\nFor SAML, create or select the enterprise application, configure its Identifier\nand Reply URL from this environment, then load the Microsoft Entra Identifier,\nlogin URL and current signing certificate into the SAML connection. Review the\nprovider's claims before authoring role or group mappings.\n\n- [Microsoft Entra OIDC application setup](https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/add-application-portal-setup-oidc-sso)\n- [Microsoft Entra SAML application setup](https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/add-application-portal-setup-sso)\n- [Microsoft Entra redirect URI rules](https://learn.microsoft.com/en-us/entra/identity-platform/how-to-add-redirect-uri)\n\n### Okta\n\nCreate a private OIDC or SAML app integration and initially assign only the\npilot people or groups. For OIDC, choose a **Web Application**, register the\nexact sign-in redirect URI, retain authorization code, and keep PKCE S256. Copy\nthe client ID, client secret and exact issuer used by that authorization server.\nDo not enable a wildcard redirect merely to avoid maintaining environment URLs.\n\nFor SAML, enter this environment's ACS URL and service-provider entity ID, then\nload Okta's Identity Provider issuer, sign-on URL and signing certificate into\nthe application connection. Map claims and groups explicitly; an Okta\nassignment decides who may reach the provider integration, while the\napplication membership and roles still decide application access.\n\n- [Okta OIDC app integration](https://help.okta.com/en-us/content/topics/apps/apps_app_integration_wizard_oidc.htm)\n- [Okta SAML app integration](https://help.okta.com/en-us/content/topics/apps/apps_app_integration_wizard_saml.htm)\n- [Okta SAML field reference](https://help.okta.com/en-us/content/topics/apps/aiw-saml-reference.htm)\n\n### Google Workspace or Cloud Identity\n\nFor OIDC, configure a web OAuth client with the exact authorized redirect URI\nand use Google's published issuer/discovery information. The provider can\nauthenticate Google accounts beyond one Workspace domain, so the application\nconnection's explicit allowed-domain list and the organization's membership\npolicy remain important boundaries.\n\nFor SAML, add a custom SAML app, copy Google's IdP entity ID, SSO URL and\ncertificate into this connection, then enter the application's ACS URL and\nentity ID in Google. Start with the service disabled or assigned to a pilot\norganizational unit/group, depending on the provider controls available to the\norganization.\n\n- [Google OpenID Connect guide](https://developers.google.com/identity/openid-connect/openid-connect)\n- [Google custom SAML application setup](https://support.google.com/a/answer/6087519)\n\n> **Do not paste credentials, private keys or complete certificates into a\n> ticket or screenshot.** Use the protected administration surfaces to exchange\n> sensitive material and share only non-secret identifiers for diagnosis.\n\n## Verify before enabling broadly\n\nEnable the connection for a controlled test, but do not make it default. Start\nfrom the application's sign-in journey and verify:\n\n1. the intended provider and environment receive the request;\n2. the provider accepts the controlled person under its expected policy;\n3. the application accepts the returned issuer/entity, audience, destination,\n signature and time checks;\n4. the stable subject maps to the intended application person;\n5. the person enters the intended organization with the expected role;\n6. one expected action succeeds and one action outside that authority is\n refused; and\n7. the independent recovery administrator still signs in.\n\nRecord non-secret identifiers, time, outcome and correlation evidence. Continue with\n[Roll out SSO and keep a recovery path](/access-and-identity/sso-rollout-and-recovery)\nbefore making it the default. Never include a password, client secret, private\nkey, complete assertion, authorization code or session cookie in the evidence.`,\n },\n {\n managedPath: 'access-and-identity/sso-rollout-and-recovery.md',\n unitRef: 'technical-documentation:unit/sso-rollout-and-recovery',\n sourceRefs: [\n 'saas-technical-doc:engine-content/sso-rollout-and-recovery',\n 'source:consumer-fact:access-single-sign-on',\n ],\n markdown: `# Roll out SSO and keep a recovery path\n\nIntroduce a configured connection in stages so a mapping mistake or provider\noutage cannot lock every administrator out at once.\n\n| Before you begin | Successful result |\n| --- | --- |\n| The connection passes a controlled test, the application and identity-provider owners are available, and an independent administrator can enter without this connection | Representative people sign in to the right organization with expected access, the connection becomes default only after proof, and a tested recovery path remains available |\n\nThe application can offer more than one configured connection and distinguish\nenabled from default behavior:\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#markdown}}\n\n~~~mermaid\nflowchart LR\n accTitle: Roll out single sign-on in controlled stages\n accDescr: Keep an independent recovery administrator, test one controlled identity, expand to a representative pilot, make the connection default only after verification, and retain the recovery path.\n recovery[\"Verify independent administrator recovery\"] --> controlled[\"Test one controlled identity\"]\n controlled --> pilot[\"Expand to a representative pilot\"]\n pilot --> default[\"Make default after verification\"]\n default --> monitor[\"Monitor and retain recovery\"]\n controlled -.-> stop[\"Stop on unexplained difference\"]\n pilot -.-> stop\n~~~\n\nThe recovery identity must not depend on the connection being tested. Confirm it\nbefore changing the default connection, and verify it again after a material\nprovider or trust change.\n\n## Build a representative pilot\n\nDo not test only an administrator. Include the identity and access differences\nthat can reveal a mapping defect:\n\n| Pilot case | What it proves |\n| --- | --- |\n| Existing ordinary member | Stable subject mapping does not create a duplicate person |\n| Newly eligible person, when first-sign-in creation is enabled | The intended user and membership lifecycle occurs with the fallback role |\n| Person with a mapped provider role or group | The exact external value maps to the intended application role |\n| Person outside an allowed domain or mapping | The connection refuses the identity without revealing another account |\n| Person with application MFA requirements | The actual post-provider journey is observed; do not infer it from the currently non-operative \\`bypassAppMFA\\` field |\n| Independent recovery administrator | Provider outage or mapping failure does not remove all administrative access |\n\nUse controlled test identities and non-sensitive application actions. Do not\nalter a real person's provider attributes merely to make the pilot pass.\n\n## Run the staged rollout\n\n1. Test one controlled identity whose provider attributes and organization\n membership are already known.\n2. Confirm the person returns to the correct environment and organization.\n3. Verify expected application access and an expected refusal; a successful\n provider login alone is insufficient.\n4. Expand to a pilot representing the identity patterns and roles used by the\n organization.\n5. Stop on an unexplained mapping, membership or access difference.\n6. Confirm how leavers and role changes are handled manually or through SCIM;\n SSO alone does not close the application membership.\n7. Make the connection default only when the pilot and recovery path both pass.\n\n## Make the default change observable\n\nChoose a support window, communicate which people and organization are affected,\nand record the previous default connection. After the change, repeat a normal\napplication-started sign-in rather than reusing a provider URL. Verify the\nresolved person, organization, expected action and expected refusal. Monitor\nauthentication failures separately from membership/role refusals so an access\nproblem is not mistaken for a provider outage.\n\n~~~mermaid\nstateDiagram-v2\n accTitle: Keep the connection in a known operational state\n accDescr: A connection begins configured but not default, advances through controlled and representative proof, becomes default only after recovery proof, returns to validation after any trust or mapping change, and is disabled when safe verification cannot be restored.\n [*] --> ConfiguredNotDefault\n ConfiguredNotDefault --> ControlledProof: one known identity passes\n ControlledProof --> Pilot: representative identities pass\n Pilot --> Default: recovery path also passes\n Default --> ConfiguredNotDefault: trust, credential, certificate, mapping or provider change\n ConfiguredNotDefault --> Disabled: validation cannot be completed safely\n Default --> Disabled: active incident requires containment\n Disabled --> ConfiguredNotDefault: corrected configuration is ready to retest\n~~~\n\nThe loop back to validation is intentional. A renewed secret, signing\ncertificate, issuer, endpoint, claim mapping or default role changes the trust\nor access proof even when the connection keeps the same display name.\n\n## Renew credentials and signing certificates without an outage\n\n### Rotate an OIDC client secret\n\n1. Confirm whether the provider supports two simultaneously valid secrets.\n2. Create the replacement in the provider and record its owner and expiry.\n3. Update the protected, write-only client-secret field in the matching\n application environment. Never paste the secret into a change ticket.\n4. Run a fresh controlled sign-in and inspect both provider and application\n evidence.\n5. Revoke the previous secret only after the replacement succeeds and the\n rollback window has been approved.\n\nIf the provider permits only one active secret, schedule a support window,\nretain the independent administrator path, update both sides as one controlled\nchange, and test immediately.\n\n### Rotate a SAML signing certificate\n\n1. Obtain the provider's new public signing certificate and verify its\n fingerprint through an approved independent channel.\n2. When the provider and application support overlapping certificates, load the\n new certificate before the provider starts signing with it.\n3. Run **Test connection**, then complete a real sign-in.\n4. Switch the provider to the new signing key and repeat the controlled proof.\n5. Remove the old certificate only after all provider nodes use the new key and\n the overlap window has ended.\n\nThe application schema accepts more than one SAML signing certificate so a\nplanned overlap is possible. Do not replace a certificate merely because a\nticket contains a PEM block; verify the provider source and fingerprint.\n\n## Monitor both sides of the boundary\n\nCorrelate by time, person, application/connection and the provider's request or\ncorrelation identifier where available. Provider success plus application\nfailure points to response validation, mapping or membership. Provider failure\nmeans the application may never receive a response.\n\n- Microsoft Entra: [sign-in logs](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-ins)\n and [sign-in diagnostics](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-use-sign-in-diagnostics).\n- Okta: [System Log](https://help.okta.com/en-us/content/topics/reports/reports_syslog.htm).\n- Google Workspace: use the provider's authentication and SAML application\n audit/investigation views available for the organization's edition, together\n with the application audit trail.\n\n## Prepare for provider or configuration failure\n\nRecord who owns the provider and application sides of the connection, how to\nreach the independent recovery method, and which last-known-good values can be\ncompared without exposing secrets. After changing issuer, entity, audience,\nredirect, certificate, client or mapping settings, repeat the controlled test\nbefore expanding again.\n\nIf the provider is unavailable, use the independent recovery method, confirm\nthe scope of the outage and avoid changing trust values speculatively. Restore\nor correct one boundary, retest with a controlled identity, then return the\nconnection to default use. Keep the recovery method narrow and monitored; it is\nnot a shared bypass account.\n\nRetain the connection name, organization, environment, pilot cases, test times,\nnon-secret trust identifiers, mapping decisions, allowed/refused results,\ndefault-change approval and recovery proof. Exclude passwords, one-time codes,\nclient secrets, private keys, complete assertions and session cookies.`,\n },\n {\n managedPath: 'access-and-identity/sso-troubleshoot.md',\n unitRef: 'technical-documentation:unit/sso-troubleshoot',\n sourceRefs: [\n 'saas-technical-doc:engine-content/sso-troubleshoot',\n 'source:consumer-fact:access-single-sign-on',\n ],\n markdown: `# Troubleshoot single sign-on\n\nAn SSO failure can occur before the person reaches the identity provider, while\nthe provider authenticates them, when the application validates the returned\nresponse, or after sign-in when membership and roles are evaluated. Find that\nboundary first. Changing trust settings before you know the boundary can turn a\nlocal mapping problem into an outage for everyone using the connection.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Have an independent administrator recovery method, one controlled test identity, the environment, organization, connection name and approximate failure time | The failing stage and responsible configuration are identified, one narrow correction is verified, and the recovery path still works |\n\n## Locate the failing stage\n\n~~~mermaid\nflowchart TD\n accTitle: Locate a single sign-on failure without weakening trust\n accDescr: The administrator confirms that the application offers the intended connection, checks whether the identity provider accepted the request, verifies the returned response against the configured trust, then diagnoses identity mapping, organization membership and roles separately.\n start[\"Person starts from the application sign-in page\"] --> offered{\"Intended connection offered?\"}\n offered -->|No| selection[\"Check enabled state, default choice, organization and environment\"]\n offered -->|Yes| provider{\"Provider accepts request and authenticates person?\"}\n provider -->|No| providerConfig[\"Check provider-side client or service configuration\"]\n provider -->|Yes| response{\"Application accepts returned response?\"}\n response -->|No| trust[\"Check issuer or entity, audience, destination, signature and time\"]\n response -->|Yes| identity{\"Correct person and organization?\"}\n identity -->|No| mapping[\"Check stable identity mapping and membership\"]\n identity -->|Yes| access{\"Expected operation allowed?\"}\n access -->|No| authorization[\"Check membership, role and operation contract\"]\n access -->|Yes| complete[\"Record successful controlled proof\"]\n~~~\n\nStart from the application's normal sign-in page. It is the authority for the\nconnections available to this person and organization:\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#markdown}}\n\nAn enabled connection may be offered for use; a default connection may be\nselected automatically. Neither setting proves that the provider trust,\nidentity mapping or organization access is correct.\n\n## Read the symptom by boundary\n\n| Symptom | Check first | Safe response |\n| --- | --- | --- |\n| The connection is not offered | Enabled state, organization and environment | Use the application's sign-in journey; do not construct a callback URL |\n| The provider rejects the request | Provider/application identity and registered destination | Correct the matching environment's configuration |\n| The application rejects the response | Signature trust, issuer/entity, audience, timing and intended connection | Treat it as a trust failure; never disable validation |\n| Sign-in resolves the wrong person | Stable subject and identity mapping | Correct the mapping; do not match only by display name |\n| Sign-in succeeds in the wrong organization | Connection scope and membership | Select or correct the intended organization relationship |\n| Sign-in succeeds but an action is refused | Membership state, role and exact operation | Diagnose authorization separately from SSO |\n\nFor **OpenID Connect**, compare the published issuer, client identity, exact\nreturn destination and client authentication configuration for the same\nenvironment. For **SAML**, compare the provider and application entity\nidentities, response destination, audience and current signing trust. In both\nprotocols, a value from staging is not interchangeable with its production\ncounterpart even when the display names look similar.\n\n## Compare both sides before changing anything\n\n| Evidence | Provider side | Application side | What a mismatch means |\n| --- | --- | --- | --- |\n| Request destination | The app integration that received the request | Configured authorization or SSO URL | Wrong tenant, provider application or environment |\n| Return destination | Registered redirect URI or ACS URL | Current environment callback/ACS value | Provider will refuse the request or application will reject the response |\n| Trust identity | OIDC issuer or SAML IdP entity ID | Connection issuer/entity ID | Response came from a different trust boundary |\n| Intended recipient | Provider app/client or SAML audience configuration | OIDC client ID or SAML service-provider identity | Response was issued for another application |\n| Signing material | Current JWKS or SAML signing certificate | Resolved keys or configured certificates | Rotation drift, stale metadata or wrong provider |\n| Person mapping | Provider subject and mapped claims/attributes | Application identity/attribute mapping | Duplicate, missing or wrong person |\n| Access | Provider app assignment/groups | Membership, role mapping and application operation | Authentication succeeded but authorization is different |\n\nUse sanitized identifiers and fingerprints for comparison. Do not attach an ID\ntoken, SAML assertion, authorization code, client secret or session cookie.\n\n### OIDC checks\n\n- Resolve the exact issuer used by the connection and compare it byte-for-byte\n with the provider metadata for this tenant or authorization server.\n- Confirm the provider app registration contains the exact web redirect URI for\n this environment. A path, scheme, host or trailing-slash difference can be a\n different URI.\n- Confirm the client secret is current at both sides. A masked read proves only\n that a value is stored, not that it is the provider's active credential.\n- Confirm the authorization-code journey uses PKCE S256 and that the code is\n redeemed only once by the same environment.\n- Check whether the response supplies the configured email, subject and\n optional group/role claims. Correct the provider claim or mapping; never map a\n display name as the stable subject.\n\nThe application verifies an OIDC ID token's signature, issuer, audience,\nexpiration and issued-at claims when the connection resolves both a signing-key\nlocation and issuer. If either is absent, profile retrieval can follow a\ndifferent provider path, so preserve the exact connection mode in support\nevidence.\n\n### SAML checks\n\n- Compare the provider entity ID, application/service-provider entity ID, ACS\n destination and assertion audience as four distinct values.\n- Verify the response is signed by a certificate currently trusted on the\n connection and that the certificate is within its validity window.\n- Check server time before increasing clock tolerance. The supported tolerance\n is 0–300 seconds and defaults to 30 seconds; it is not a substitute for clock\n synchronization.\n- For provider-started sign-in, confirm \\`allowIdpInitiated\\` is deliberately\n enabled. The application validates the signature against matching connection\n candidates and refuses an ambiguous tenant match rather than guessing.\n- Check NameID and attribute mappings separately. A valid NameID does not prove\n that the required email or role/group attribute is present.\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#diagnosticsMarkdown}}\n\n## Use provider logs to locate the hand-off\n\n- [Microsoft Entra sign-in logs](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-ins)\n show the person, application, target resource and provider result. Use\n [sign-in diagnostics](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-use-sign-in-diagnostics)\n for a failed event.\n- [Okta System Log](https://help.okta.com/en-us/content/topics/reports/reports_syslog.htm)\n exposes time, actor, target and event details for the provider side.\n- For Google Workspace or Cloud Identity, inspect the organization's SAML or\n authentication audit/investigation view for the affected custom app and time.\n\nIf the provider has no matching attempt, investigate connection selection and\nthe outbound request. If the provider records success but the application has\nno accepted session, investigate return destination and response validation.\nIf both record success, move to identity mapping, membership and roles.\n\n## Test one correction safely\n\n1. Preserve the last-known-good non-secret identifiers before editing.\n2. Change one configuration boundary at a time.\n3. Start a fresh sign-in from the application with the controlled identity; do\n not replay an old response or reuse a callback URL.\n4. Verify the resolved person, organization and one expected allowed action.\n5. Verify an expected refusal so the test does not prove over-broad access.\n6. Confirm the independent recovery administrator can still enter.\n\nA completed provider login proves only that the provider accepted the person.\nIt does not prove that the application accepted the response or that the\nperson's organization membership and role authorize the requested work.\n\n## Escalate without exposing credentials\n\nPreserve the time, environment, organization, connection name, protocol,\nfailing stage, sanitized message and correlation identifier. State whether one\nperson or all tested people are affected and whether the connection ever\nworked in this environment. Do not collect a password, one-time code, private\nkey, client secret, complete certificate chain, authorization code, session\ncookie or full SAML/OIDC response in an ordinary ticket.\n\nUse the independent recovery method if administrators cannot enter through SSO.\nRestore or correct the connection, retest with the controlled identity, and only\nthen return it to default use. SSO recovery must not create a new membership or\nbroaden a role merely to make the sign-in test pass.`,\n },\n {\n managedPath: 'access-and-identity/api-keys.md',\n unitRef: 'technical-documentation:unit/api-keys',\n sourceRefs: [\n 'saas-technical-doc:engine-content/api-keys',\n 'source:consumer-fact:access-api-keys',\n ],\n markdown: `# API keys\n\nAPI keys authenticate unattended software such as a server, scheduled job or\nautomation. They do not represent a signed-in person and do not bypass roles,\norganization boundaries, feature state or an operation's API-key policy.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Name one workload, owner, environment, organization/application scope and minimum set of operations | The workload has one independently revocable credential, performs only its intended work and leaves non-secret evidence that can be reviewed |\n\n## Choose a machine identity deliberately\n\n| Need | Use | Avoid |\n| --- | --- | --- |\n| One unattended workload acts inside one organization | Organization API key when the exact operations accept it | A person's session or an application-wide key |\n| One trusted workload genuinely needs application-wide operations | Application API key when those operations explicitly accept it | Promoting an organization key after an unexplained 403 |\n| A client acts after a person authorizes it | [OAuth delegated access](/access-and-identity/oauth-provider) | Collecting the person's password or reusing their browser session |\n| A person works interactively | Their own [sign-in method](/access-and-identity/sign-in-and-mfa) | An API key shared between people |\n\nThe credential type identifies **who is acting**. It does not decide what the\nidentity may do. Key scope, assigned roles, organization visibility, feature\nstate and the operation's authentication contract are all evaluated separately.\n\n~~~mermaid\nflowchart LR\n accTitle: Manage an API key through its lifecycle\n accDescr: Choose the smallest scope and roles, create and store the secret, deploy it to one workload, verify its use, rotate it deliberately, and deactivate it when no longer needed.\n choose[\"Choose scope and minimum roles\"] --> create[\"Create and store secret\"]\n create --> verify[\"Verify one safe operation\"]\n verify --> rotate[\"Rotate deliberately\"]\n rotate --> deactivate[\"Deactivate when finished\"]\n~~~\n\nEvery key should have one understandable owner, workload, environment and\npurpose. If those cannot be identified during review, replace or deactivate the\ncredential rather than leaving anonymous production access active.\n\nThe lifecycle is operational, not merely cryptographic: somebody must know\nwhere the current secret is deployed, how to prove a replacement, when the\nprevious secret stops working and how to deactivate the key during an incident.\n\n## Follow the API-key journey\n\n| Your next task | Start here | Successful result |\n| --- | --- | --- |\n| Choose scope and create a key | [Create and store an API key](/access-and-identity/api-keys-create-and-store) | One independently identifiable key can perform only the intended operations |\n| Replace a key or end its access | [Rotate, expire or deactivate an API key](/access-and-identity/api-keys-lifecycle) | Workloads move to the intended secret and the previous access ends when expected |\n| Investigate a refused request | [Troubleshoot an API key](/access-and-identity/api-keys-troubleshoot) | Transport, lifecycle, scope and authorization failures are distinguished without broadening access |\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#markdown}}\n\nThe prefix identifies scope; it does not grant authority. The key's roles and\nthe requested operation remain decisive.\n\n## Understand the two scopes and three states\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#scopeComparisonMarkdown}}\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#statusMarkdown}}\n\nThe HTTP standard defines the [\\`Authorization\\` request field](https://www.rfc-editor.org/rfc/rfc9110#field.authorization),\nwhile OAuth bearer tokens use the separate [\\`Bearer\\` authentication scheme](https://www.rfc-editor.org/rfc/rfc6750#section-2.1).\nThis application's API-key contract uses the \\`Authorization\\` field with the\nraw key and **no scheme**. Treat that as application-specific wire syntax: do\nnot prepend \\`Bearer\\`, put the key in a query string, or rename the field.\n\n## Review every key as access\n\nAt creation and at each review, record:\n\n- the accountable owner and workload;\n- environment and organization/application scope;\n- intended operations and minimum assigned roles;\n- non-secret key prefix, status, expiry and the available application/workload\n evidence (the current runtime does not populate per-key last-used statistics);\n- secrets-manager location and deployment owners;\n- rotation/deactivation procedure and next review date.\n\nDo not retain the complete key in that record. If a key is unused, ownerless,\ndeployed to an unknown number of workloads or broader than its documented\npurpose, replace or deactivate it rather than accepting the ambiguity.`,\n },\n {\n managedPath: 'access-and-identity/api-keys-create-and-store.md',\n unitRef: 'technical-documentation:unit/api-keys-create-and-store',\n sourceRefs: [\n 'saas-technical-doc:engine-content/api-keys-create-and-store',\n 'source:consumer-fact:access-api-keys',\n ],\n markdown: `# Create and store an API key\n\nCreate a separate machine credential for one workload and environment. This\ntask is for the integration owner and the administrator authorized to choose its\nscope and roles.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Know the workload owner, environment, required organization scope and minimum operations | The secret is stored outside code and a safe request proves only the intended access |\n\n~~~mermaid\nflowchart TD\n accTitle: Create and hand over one least-privilege API key\n accDescr: The integration owner defines one workload and scope, the administrator assigns minimum roles and an expiry or review date, the one-time secret is stored directly in a secrets manager, the workload performs a safe positive and negative proof, and only non-secret evidence is retained.\n workload[\"Name one workload, owner and environment\"] --> scope[\"Choose organization or application scope\"]\n scope --> roles[\"Assign minimum roles for documented operations\"]\n roles --> create[\"Create key with expiry or review date\"]\n create --> store[\"Store one-time secret directly in secrets manager\"]\n store --> deploy[\"Deploy to the one owning workload\"]\n deploy --> proof[\"Verify intended success and expected refusal\"]\n proof --> evidence[\"Retain prefix, owner and lifecycle evidence\"]\n~~~\n\nThe diagram deliberately has no “copy to a ticket” or “send to another team”\nstep. The complete secret should move from the creation response to protected\nstorage and then to the owning workload through its normal secret-delivery path.\n\n## Choose the smallest scope\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#markdown}}\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#scopeComparisonMarkdown}}\n\n- Choose an **organization key** for a workload acting inside one organization.\n- Choose an **application key** only for a workload that genuinely needs\n application-wide scope and whose operation contracts accept it.\n\nDo not select application scope merely because an organization key receives a\nrefusal. First verify the role, feature and operation contract.\n\nBefore creation, list the exact business operations the workload performs and\nmap each to its API reference authentication/role contract. Remove speculative\nfuture permissions. When operations span unrelated purposes, create separate\nkeys so one workflow can be rotated or contained without interrupting another.\n\n## Name and create the credential\n\nUse a name that identifies the system, environment and purpose—for example\n“Production invoice reconciliation”. Record its accountable owner, intended\noperations, assigned roles, expiry or review date. Do not share one key between\nunrelated workloads: independent keys make rotation, incident containment and\naudit attribution possible.\n\nThe complete secret is returned at creation and may not be recoverable later.\nMove it directly into the workload's secrets manager. Keep only its visible\nprefix for ordinary identification. Never retain the full key in source code, a\nbrowser bundle, URL, screenshot, ticket or ordinary log.\n\nIf the creation response is lost before protected storage succeeds, do not ask\nsupport to recover the secret. Replace the credential through the approved\nlifecycle, record the abandoned prefix and ensure the unusable key is inactive.\n\n## Deliver the secret through the workload's secret system\n\nChoose the system that already controls secrets for the workload. Do not add a\nnew copy merely to follow this guide.\n\n| Workload | Safe delivery pattern | What to verify |\n| --- | --- | --- |\n| AWS-hosted service | Store the value in AWS Secrets Manager and let the workload retrieve it through a narrow workload identity | Only the owning workload can read the secret; retrieval and rotation are monitored. See [AWS Secrets Manager best practices](https://docs.aws.amazon.com/secretsmanager/latest/userguide/best-practices.html). |\n| Azure-hosted service | Store the value in Azure Key Vault, separate application/environment boundaries and attach owner/expiry metadata outside the value | The workload identity can read this secret but cannot administer the vault. See [Azure Key Vault secret guidance](https://learn.microsoft.com/en-us/azure/key-vault/secrets/secure-secrets). |\n| Google Cloud workload | Store the value in Secret Manager in the workload's environment project and grant the minimum IAM access to that secret | Production and non-production projects and identities remain separate. See [Google Secret Manager best practices](https://docs.cloud.google.com/secret-manager/docs/best-practices). |\n| Kubernetes workload | Prefer an approved external secret store; otherwise encrypt Secrets at rest, restrict RBAC and expose the value only to the container that needs it | No manifest or base64 value enters source control, and unrelated containers cannot read it. See [Kubernetes Secrets good practices](https://kubernetes.io/docs/concepts/security/secrets-good-practices/). |\n| GitHub Actions workflow | Use an environment or repository secret restricted to the intended workflow/environment | The value is referenced through the secrets context and never echoed; log redaction is treated as defense in depth, not proof of non-disclosure. See [GitHub Actions secrets](https://docs.github.com/en/actions/concepts/security/secrets). |\n\nThe [OWASP Secrets Management guidance](https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html)\ndescribes the broader lifecycle: centralized ownership, least-privilege access,\nautomated delivery, rotation, revocation, expiry, auditing and recovery. Use the\napplication lifecycle below as the credential-side half of that operating model.\n\n## Send and verify the key\n\nSend the complete opaque value in the standard header, without a \\`Bearer\\`\nscheme:\n\n~~~text\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#requestHeader}}\n~~~\n\nUse an operation whose generated API reference explicitly permits API-key\naccess. Verify a safe read in the correct environment and organization before\nenabling writes.\n\nWith the base URL and key injected by the deployment system, a first read has\nthis shape. Replace \\`<operation-path>\\` with the exact path from the generated\nAPI reference; do not paste a real key into the command or shell history.\n\n~~~bash\ncurl --request GET \\\\\n --url \"$APPLICATION_API_BASE/<operation-path>\" \\\\\n --header \"Accept: application/json\" \\\\\n --header \"Authorization: $APPLICATION_API_KEY\"\n~~~\n\nThe workload variable must contain the complete organization- or\napplication-scoped value described by the source-derived table above. A\n\\`Bearer\\` prefix changes the bytes and causes authentication to fail.\n\nThen verify an expected refusal: choose an operation outside the intended role\nwithout probing another customer's known identifier. The successful read proves\nconnectivity; the refusal proves that the key did not receive broader authority\nthan intended.\n\n## Complete the handover\n\n1. Confirm every workload instance reads the intended secrets-manager version.\n2. Confirm ordinary logs show operation, outcome and correlation evidence but\n never the Authorization header.\n3. Record the key's non-secret prefix, owner, scope, roles, expiry/review date\n and deployed workload.\n4. Prove the owner can rotate and deactivate the key without affecting an\n unrelated integration.\n\nDo not enable production writes until this handover is repeatable.`,\n },\n {\n managedPath: 'access-and-identity/api-keys-lifecycle.md',\n unitRef: 'technical-documentation:unit/api-keys-lifecycle',\n sourceRefs: [\n 'saas-technical-doc:engine-content/api-keys-lifecycle',\n 'source:consumer-fact:access-api-keys',\n ],\n markdown: `# Rotate, expire or deactivate an API key\n\nReplace a machine credential without losing control of which secret works. Use\nrotation for a planned, bounded handover; use immediate rotation or deactivation\nfor suspected exposure; and use expiry when access has a known end date.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Identify the key by its non-secret prefix, owner, workload, scope, roles and deployed instances; have an approved secrets-manager destination | Every intended instance uses the replacement, the previous secret stops at the chosen time, expected access still works and unrelated access remains refused |\n\nThe key presentation identifies its scope, not its authority:\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#markdown}}\n\nConfirm that you are changing the intended organization or application key\nbefore reissuing any secret. A prefix is safe to use for identification, but it\nis not enough on its own: compare the owner, workload and environment too.\n\n## Choose the lifecycle action\n\n| Situation | Action | Important consequence |\n| --- | --- | --- |\n| Planned replacement with a short deployment window | **Rotate** with an explicit future invalidation time | Current and previous secrets can overlap only until that chosen time |\n| Suspected disclosure and the workload can switch now | **Rotate immediately** | Immediate rotation is the default when no future invalidation time is chosen; the previous secret stops working at cutover |\n| Suspected disclosure and workload ownership is uncertain | **Deactivate** | Neither the current nor retained previous secret can authenticate while the key is inactive |\n| Workload is permanently retired | **Deactivate** and remove its deployed secret | The key remains identifiable for review but cannot authenticate |\n| Temporary credential has a known end | Set an **expiry** at creation; extend it only after a documented review | Once expired, the key cannot be reactivated; replace it if access is approved again |\n| An intentional open-ended overlap is truly required | **Regenerate**, with a separately controlled follow-up rotation | The previous secret remains valid until a later reissue; regeneration does not contain a leaked credential |\n\n## Know the maintained lifecycle operations\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#statusMarkdown}}\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#lifecycleMarkdown}}\n\n~~~mermaid\nflowchart TD\n accTitle: Choose the safe API-key lifecycle action\n accDescr: A planned handover uses rotation and verification. Suspected compromise requires prompt old-secret invalidation or deactivation. Finished access is deactivated, while a time-bounded credential is allowed to expire.\n reason{\"Why must access change?\"}\n reason -->|\"Planned replacement\"| rotate[\"Rotate with explicit handover\"]\n reason -->|\"Suspected exposure\"| contain[\"Invalidate old secret promptly or deactivate\"]\n reason -->|\"Workload retired\"| deactivate[\"Deactivate key\"]\n reason -->|\"Known end time\"| expiry[\"Set or extend explicit expiry\"]\n~~~\n\n## Run a planned rotation\n\nRotation keeps the same credential record, owner, scope and roles while issuing\na new complete secret. The outgoing secret moves into a single previous-secret\nslot and remains usable only until the selected invalidation time. If no future\ntime is selected, the operation defaults to **now**, which is an immediate\ncutover.\n\n1. Inventory every production instance, scheduled job and deployment that reads\n this key. Do not rotate while ownership is unknown.\n2. Choose the shortest practical invalidation time. Record the reason, owner\n and planned end of overlap.\n3. Perform the rotation and move the one-time replacement directly into the\n approved secrets-manager entry. Never paste it into the change record.\n4. Roll out the new secret to every known instance and verify a safe operation\n in the intended environment and scope.\n5. Before the deadline, confirm every instance reports the replacement version\n and no deployment still depends on the outgoing secret.\n6. After invalidation, verify that the replacement still succeeds and that the\n previous secret is refused. Record only prefixes, times, outcomes and\n correlation evidence.\n\nIf an instance cannot move before the chosen time, stop and make a conscious\navailability-versus-exposure decision. Do not silently extend an overlap whose\nowner or purpose is unclear.\n\n## Understand regeneration before using it\n\n> **Regeneration is not incident containment.** An open-ended regenerate\n> operation leaves the previous secret valid until a later reissue replaces the\n> overlap state. If the key may be compromised, deactivate it or rotate with\n> prompt invalidation.\n\nRegeneration can support a deliberately staged migration when the old secret\ncannot yet have a bounded end time, but it creates two live secrets. Before\nusing it, document why a normal bounded rotation is impossible, who owns the\nfollow-up cutover and when the later rotation will occur. Verify both the new\ndeployment and the eventual rejection of the previous secret; issuing a new\nsecret is not completion.\n\n## Contain suspected exposure\n\nWhen a complete secret may have reached source control, a browser bundle, a\nticket, an ordinary log or an unauthorized person:\n\n1. Preserve non-secret time, environment, prefix and workload evidence.\n2. Deactivate the key when deployment ownership is uncertain, or rotate with\n immediate invalidation when the approved workload can switch safely.\n3. Remove the exposed value from every deployment and storage location. Treat\n source-history or log cleanup as a separate containment task; rotation alone\n does not remove copied material.\n4. Review the application audit trail and workload/provider logs for the\n affected period, using the key identifier, prefix, operation and correlation\n evidence—not the complete secret. Do not infer inactivity from the current\n per-key usage-statistics response.\n5. Restore only the minimum intended roles and operations with a protected\n replacement. Verify an expected refusal as well as a successful request.\n\n## Handle status and expiry\n\nAn inactive key cannot authenticate, including through a retained previous\nsecret. Reactivation is permitted only for an **Inactive** key; an **Expired**\nkey is terminal and cannot be reactivated. If access is approved again after\nexpiry, create a new least-privilege credential with a new review decision.\n\nExpiry is enforced when the key authenticates. Treat the key as unusable after\nthat time even if a list view has not yet changed its stored status label.\nExtend an existing expiry only when the same owner, workload, scope, roles and\nbusiness need have been reviewed. Extension changes the time boundary; it does\nnot rotate secret material or repair an ownerless key.\n\n## Close the change with evidence\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#usageStatisticsLimitationMarkdown}}\n\nUntil per-key tracking exists, prove deployment and retirement from controlled\nrequests, application audit evidence and the workload's own secret-access and\nexecution logs. A page of zero counters is not a safe deletion decision.\n\nRetain a non-secret lifecycle record containing:\n\n- key identifier or visible prefix, scope, owner and workload;\n- action taken, reason, approver and environment;\n- replacement deployment time and every affected instance;\n- chosen previous-secret invalidation time;\n- successful expected operation and expected refusal;\n- confirmation that the previous secret no longer authenticates; and\n- incident or change correlation identifier and next review date.\n\nNever attach the current or previous complete secret, Authorization header or\nsecrets-manager value to lifecycle evidence.`,\n },\n {\n managedPath: 'access-and-identity/api-keys-troubleshoot.md',\n unitRef: 'technical-documentation:unit/api-keys-troubleshoot',\n sourceRefs: [\n 'saas-technical-doc:engine-content/api-keys-troubleshoot',\n 'source:consumer-fact:access-api-keys',\n ],\n markdown: `# Troubleshoot an API key\n\nDiagnose the failed decision in order: transport, credential lifecycle, scope,\nrole and operation policy. Do not rotate or broaden a credential before you\nknow which decision failed.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Preserve the environment, operation, approximate time, correlation details and non-secret key prefix | One narrow correction makes a safe request succeed, and the workload still cannot exceed its intended scope |\n\n~~~mermaid\nflowchart TD\n accTitle: Diagnose an API key from transport to operation access\n accDescr: The integration owner confirms the environment and authorization header, matches the non-secret prefix to an active unexpired key, verifies organization or application scope and assigned roles, and finally checks whether the exact operation accepts API-key authentication.\n symptom[\"Request is refused or resource is missing\"] --> environment[\"Confirm environment and operation\"]\n environment --> transport{\"Header contains current opaque key?\"}\n transport -->|No| correct[\"Correct secret delivery without logging it\"]\n transport -->|Yes| lifecycle{\"Key active and unexpired?\"}\n lifecycle -->|No| replace[\"Use approved rotation or replacement\"]\n lifecycle -->|Yes| scope{\"Scope and roles match the task?\"}\n scope -->|No| assignment[\"Correct the narrow assignment\"]\n scope -->|Yes| contract[\"Check exact operation authentication contract\"]\n contract --> proof[\"Repeat one safe request and verify result\"]\n~~~\n\nThe non-secret prefix helps identify the credential record; it cannot prove\nthat the workload received the current complete secret.\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#usageStatisticsLimitationMarkdown}}\n\nDo not diagnose an apparently unused key from those counters. Correlate the\nworkload's execution logs, secret-access logs, application audit trail and one\ncontrolled request instead.\n\nThe request must carry the complete opaque value in this maintained header\nshape:\n\n~~~text\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#requestHeader}}\n~~~\n\n| Result | Check first | Safe response |\n| --- | --- | --- |\n| **401 Unauthorized** | Header spelling, complete secret, absence of \\`Bearer\\`, key status, expiry and environment | Correct transport or replace an inactive, expired or revoked key |\n| **403 Forbidden** | Key roles, scope, feature entitlement and whether the operation accepts API keys | Correct the narrow assignment or integration design |\n| **404 Not Found** | Resource identifier and organization visibility | Confirm scope without assuming a hidden resource exists |\n| Requests alternate between success and 401 | Secret version on every workload replica or job runner | Finish deployment of the current secret, then retire the previous one deliberately |\n\n## Isolate the failing decision\n\n1. Confirm the workload targets the expected environment.\n2. Confirm the standard authorization header contains the current complete\n opaque key and no scheme.\n3. Compare the non-secret prefix with the intended credential record.\n4. Check whether rotation recently created a new secret and whether every\n workload instance received it.\n5. Check active status and expiry. An expired or inactive key must not\n authenticate even if its record remains visible.\n6. Check organization or application scope and assigned roles.\n7. Check the exact operation's generated authentication contract. Some\n operations intentionally refuse API-key access.\n8. Repeat one read-only or otherwise safe request and verify the business result\n in the intended scope.\n\n## Choose the repair that matches the failure\n\n- **Transport failure:** correct the secrets-manager reference or header\n construction. Never print the value to compare it.\n- **Old secret after rotation:** deploy the new value everywhere and verify it\n before the previous value reaches its invalidation time.\n- **Inactive, expired or compromised key:** use the approved lifecycle action;\n do not reactivate a key whose owner or exposure is uncertain.\n- **Wrong scope or role:** change only the assignment needed by the documented\n workload. Re-run an expected refusal as well as the success proof.\n- **Operation rejects API keys:** use the supported human or delegated-client\n journey. A broader API key does not change the operation's authentication\n policy.\n\nNever replace a narrow key with a broadly privileged key merely to silence an\nauthorization error. That turns a diagnosable assignment problem into a larger\nsecurity exposure.\n\n## Escalate without exposing the credential\n\nProvide the environment, operation, HTTP result, approximate time, correlation\nidentifier, non-secret key prefix, lifecycle state and whether rotation was in\nprogress. Never include the complete key, authorization header, secret-manager\nvalue or a screenshot containing them.`,\n },\n {\n managedPath: 'access-and-identity/oauth-provider.md',\n unitRef: 'technical-documentation:unit/oauth-provider',\n sourceRefs: [\n 'saas-technical-doc:engine-content/oauth-provider',\n 'source:consumer-fact:access-oauth-clients',\n ],\n markdown: `# OAuth provider and delegated access\n\nUse OAuth when software needs its own client identity or needs to act after a\nperson authorizes it. The integration does not receive the person's password or\ncopy their browser session.\n\nThis journey applies only when the application publishes an OAuth authorization\nserver. Its discovery metadata is authoritative for issuer identity, endpoints,\nsupported grants and onboarding. Do not construct those values from examples.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Know who owns the integration, which environment it runs in, whether it acts as itself or for a person, and which application operations it needs | One independently registered client uses the published flow, carries only the intended roles and can be reviewed or revoked without affecting another integration |\n\n## Choose whose authority the client uses\n\n~~~mermaid\nflowchart TD\n accTitle: Choose an OAuth client journey by who authorizes the work\n accDescr: A backend workload that acts as itself uses an advertised machine grant and its own client roles. A client that acts for a person uses the advertised authorization journey, exact registered redirects and user consent when required; the final operation remains bounded by the client and person.\n need{\"Whose authority should the integration use?\"}\n need -->|Its own machine identity| machine[\"Register a workload client\"]\n machine --> machineGrant[\"Use an advertised machine grant\"]\n machineGrant --> machineRoles[\"Authorize operations with client roles\"]\n need -->|A person authorizes the client| delegated[\"Register a delegated client\"]\n delegated --> redirect[\"Use exact redirects and the published browser flow\"]\n redirect --> consent[\"Person approves or denies when consent is required\"]\n consent --> combined[\"Operation is bounded by client roles and the person's context\"]\n~~~\n\n- Choose a **machine client** for a backend process whose work should be\n attributable to the integration itself. Do not use an administrator's\n personal browser session for unattended work.\n- Choose **delegated access** when the operation should remain connected to the\n person who approved it. The client must send the person through the published\n authorization journey; collecting their password is never an alternative.\n- Use an **API key** instead when the exact API operation supports that simpler\n machine credential and no OAuth delegation or client lifecycle is needed.\n\n## Understand the four independent decisions\n\n| Decision | What it controls | What it does not do |\n| --- | --- | --- |\n| Grant | Whether the client acts as itself or uses a person's authorization journey | It does not grant an application role |\n| Client class and token method | Whether the runtime can protect a secret and how it authenticates to the token endpoint | A public client does not become confidential by embedding a secret in shipped code |\n| Identity scopes | Which supported identity claims the client may request | They do not authorize business operations |\n| Roles | Which application operations the client may perform | They do not replace the person's membership in a delegated journey |\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#markdown}}\n\nThe client can belong to an organization or to the application. That scope\nchooses the machine identity and administrative boundary; it does not make a\nclient more trusted merely because it is application-scoped.\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#scopeComparisonMarkdown}}\n\nRegister a separate client for each integration and environment. Redirects,\nissuer identity and credentials are environment-specific security boundaries,\nnot values to normalize or copy between deployments.\n\n## Start from discovery, not guessed endpoint paths\n\nThe authorization server publishes two equivalent metadata entry points:\n\n- OAuth authorization-server metadata at\n \\`/.well-known/oauth-authorization-server\\`;\n- OpenID Connect discovery at \\`/.well-known/openid-configuration\\`.\n\nFetch one from the **API issuer origin** and use the absolute endpoint values it\nreturns. The authorization endpoint is a browser-facing application page; the\ntoken, key, user-information, revocation and logout endpoints belong to the API\nissuer. They are deliberately not all under one hand-constructed path.\n\n~~~bash\nAPPLICATION_OAUTH_ISSUER=\"https://api.example.invalid\"\n\ncurl --fail --silent --show-error \\\n \"$APPLICATION_OAUTH_ISSUER/.well-known/oauth-authorization-server\"\n~~~\n\nCheck the returned \\`issuer\\` exactly. Then read the advertised grants,\n\\`code_challenge_methods_supported\\`, token authentication methods, registration\nendpoint and resource-indicator support before configuring the client. A\nmissing optional field means that capability is not advertised in this\nenvironment.\n\n~~~mermaid\nsequenceDiagram\n accTitle: Discover the authorization server before choosing a client flow\n accDescr: The integration starts from a resource or issuer, loads maintained metadata, selects only advertised registration and grant capabilities, and then uses the absolute endpoints returned by that metadata.\n participant Client as Integration client\n participant Resource as Protected resource\n participant AS as Authorization server\n Client->>Resource: Request protected operation\n Resource-->>Client: 401 plus protected-resource metadata when applicable\n Client->>Resource: Load protected-resource metadata\n Resource-->>Client: Authorization-server issuer and resource identifier\n Client->>AS: Load OAuth or OIDC metadata\n AS-->>Client: Issuer, endpoints, grants, PKCE and registration capabilities\n Client->>Client: Select supported registration and grant\n~~~\n\n## Use the protocol vocabulary consistently\n\n| Published element | Why the client needs it | Validation to retain |\n| --- | --- | --- |\n| \\`issuer\\` | Identifies the authorization server that produced the response and tokens | Exact string match; do not normalize hosts, paths or trailing slashes |\n| \\`authorization_endpoint\\` | Sends the person's browser through sign-in and consent | Use only the absolute discovered URL and preserve transaction state |\n| \\`token_endpoint\\` | Exchanges a machine credential, authorization code or refresh token | Use the registered client method and never log request credentials or returned tokens |\n| \\`jwks_uri\\` | Publishes public verification keys for signed tokens | Validate signature, algorithm, issuer, audience and time claims at the consuming service |\n| \\`resource\\` | Names the protected API, MCP server or A2A endpoint the token is meant for | Use the canonical advertised resource URI in both authorization and token requests when required |\n| \\`revocation_endpoint\\` | Ends a token authorization through the authenticated client lifecycle | Treat a successful no-oracle response as request acceptance, then verify the protected operation is refused |\n\nThe main standards behind those fields are [OAuth authorization-server metadata\n(RFC 8414)](https://www.rfc-editor.org/rfc/rfc8414), [PKCE (RFC\n7636)](https://www.rfc-editor.org/rfc/rfc7636), [OAuth resource indicators (RFC\n8707)](https://www.rfc-editor.org/rfc/rfc8707), [authorization-response issuer\nidentification (RFC 9207)](https://www.rfc-editor.org/rfc/rfc9207), [token\nrevocation (RFC 7009)](https://www.rfc-editor.org/rfc/rfc7009) and [OpenID\nConnect Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html).\nThe environment's metadata is still the authority for which optional\ncapabilities are enabled here.\n\n## When the protected resource is an MCP server\n\nDo not register an MCP client by guessing an OAuth endpoint. The [MCP\nauthorization specification](https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization)\nstarts from the protected resource, follows its RFC 9728 metadata to the\nauthorization server, and then chooses a registration mechanism in advertised\norder. In this application:\n\n1. use pre-registered client information when an administrator supplied it;\n2. use a Client ID Metadata Document only when metadata advertises support;\n3. use dynamic client registration only when a \\`registration_endpoint\\` is\n advertised; otherwise the route is intentionally unavailable;\n4. send the exact MCP endpoint as the RFC 8707 \\`resource\\` in the authorization\n and token requests.\n\nA dynamically registered client is deliberately **public, PKCE-only,\nauthorization-code-only, consent-required, role-free and identity-scope\nlimited**. That is an onboarding mechanism for a person-delegated MCP client,\nnot a way to mint an unattended privileged machine identity. Continue with the\n**MCP integration guide** — published under Integrations when the application\nexposes an MCP tool surface — for resource discovery and client setup.\n\n## Follow the OAuth client journey\n\n| Your next task | Start here | Successful result |\n| --- | --- | --- |\n| Define a new integration client | [Register an OAuth client](/access-and-identity/oauth-register-client) | One environment-specific client has the correct grant, class, roles and redirects |\n| Let a person authorize a client | [Authorize delegated access](/access-and-identity/oauth-authorize-delegated-access) | The person consents when required and the client receives no more authority than intended |\n| Review, rotate or revoke an active client | [Operate and revoke OAuth clients](/access-and-identity/oauth-operate-and-revoke) | Credential and authorization changes take effect without silently switching identities |\n\nBegin with the smallest safe proof: load the environment's discovery metadata,\ncomplete the selected flow with a controlled identity or workload, call one\nread-only operation and verify both the intended success and an expected\nrefusal. Do not add production writes until token storage, revocation,\nambiguous-outcome recovery and support ownership are defined.`,\n },\n {\n managedPath: 'access-and-identity/oauth-register-client.md',\n unitRef: 'technical-documentation:unit/oauth-register-client',\n sourceRefs: [\n 'saas-technical-doc:engine-content/oauth-register-client',\n 'source:consumer-fact:access-oauth-clients',\n ],\n markdown: `# Register an OAuth client\n\nCreate one client identity for one integration and environment. Record its\nowner, purpose, grant, roles, redirect URIs, token authentication method,\nconsent posture and review date.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Confirm that the application advertises an OAuth provider and choose whether the client acts as itself or after a person authorizes it | The registered client matches its runtime, can protect any required secret and uses only owned redirect destinations |\n\n~~~mermaid\nflowchart TD\n accTitle: Register one OAuth client with an explicit authority boundary\n accDescr: The integration owner identifies one environment and operating model, chooses a machine or delegated grant, protects a machine secret or classifies a delegated client as public or confidential, selects identity scopes and application roles separately, registers exact redirects, stores one-time secret material when applicable, and proves expected success and refusal.\n owner[\"Name integration owner, purpose and environment\"] --> authority{\"Acts as itself or for a person?\"}\n authority -->|\"Itself\"| machine[\"Choose an advertised machine grant\"]\n authority -->|\"For a person\"| delegated[\"Choose the advertised authorization journey\"]\n machine --> machineSecret[\"Protect the machine client secret\"]\n delegated --> clientClass[\"Choose public or confidential code client\"]\n machineSecret --> permissions[\"Separate identity scopes from application roles\"]\n clientClass --> permissions\n permissions --> redirects[\"Register exact owned redirects when interactive\"]\n redirects --> store[\"Protect one-time secret when confidential\"]\n store --> proof[\"Verify expected success and refusal\"]\n~~~\n\nRegister a separate client when the owner, environment, redirect surface or\nbusiness purpose differs. This preserves attribution and lets one integration\nbe rotated or retired without interrupting another.\n\n## Use an advertised onboarding path\n\nOAuth discovery is the authority for the current environment's provider\nidentity, supported grants and onboarding capabilities. An administrator-managed\nclient is approved inside the application. A dynamically registered client is\nself-described and receives a more cautious trust posture; use dynamic\nregistration only when the environment advertises it and the client can follow\nthe complete published flow. Do not probe an undocumented registration route.\n\n## Choose the allowed grant and client class\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#markdown}}\n\nChoose the administrative scope before choosing grants:\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#scopeComparisonMarkdown}}\n\nThe client form carries the following maintained security meanings. The API\nreference remains authoritative for the exact request shape and route in this\napplication.\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#clientConfigurationMarkdown}}\n\nUse a supported machine-to-machine grant when a backend service acts as itself.\nUse a supported authorization-code journey when a web, native, CLI or agent\nclient acts after a person authorizes it.\n\n- A **machine client** authenticates with its issued client secret. Run it only\n where that secret can be protected and delivered through a secrets manager.\n- A delegated **public client** cannot safely retain a client secret—for example browser\n or installed software. Use the published proof mechanism instead of embedding\n a pretend secret in the client package.\n- A delegated **confidential client** runs where its secret can be protected. Store that\n secret in a server-side secrets manager and authenticate to the token endpoint\n using the configured method.\n\n| Registration decision | Record | Common error |\n| --- | --- | --- |\n| Grant | Machine identity or person-delegated journey | Enabling every grant “for flexibility” |\n| Application roles | Minimum operations the client itself may perform | Treating identity scopes as permissions |\n| Identity scopes | Minimum identity claims needed by delegated sign-in | Requesting claims unrelated to the integration |\n| Delegated client class | Public when secret retention is impossible; confidential when server-side storage is real | Shipping a confidential secret in browser, native or distributed code |\n| Consent | Whether a person must approve this delegated client | Assuming consent can grant an administrator role |\n| Expiry/review | Known end date or accountable review date | Leaving an ownerless client active indefinitely |\n\n## Register redirect destinations exactly\n\nFor an authorization-code client, every redirect URI is an exact allowlist\nentry. Register only destinations owned by this client and environment. Never\nadd a wildcard, fragment, embedded credentials or a redirect copied from another\nenvironment. Ordinary web redirects use HTTPS; development or native forms are\nappropriate only when accepted by the administration surface and protected by\nthe published flow.\n\nRegister post-sign-out destinations separately when the client uses the\npublished sign-out journey. A sign-in return destination is not automatically a\nsafe sign-out destination. For a native client, use the supported loopback or\nprivate-application callback owned by that client and retain the transaction\nproof required by the published flow.\n\n> **A redirect URI is a security boundary, not a convenience pattern.** Review\n> its scheme, host, port and path as one exact value. Never broaden the allowlist\n> to repair an environment mismatch.\n\n### Choose a registration path deliberately\n\n| Registration path | Use it when | Trust and lifecycle consequence |\n| --- | --- | --- |\n| Administrator-managed registration | The integration has a known organization/application owner and may need machine roles or a confidential secret | An authorized administrator vouches for the client, chooses its roles and owns rotation/removal |\n| Client ID Metadata Document | A compatible client hosts maintained HTTPS metadata and discovery advertises support | The URL is the client identifier; the authorization server retrieves and validates its metadata under the deployment trust policy |\n| Dynamic client registration | Discovery exposes \\`registration_endpoint\\` and an interoperable public client needs fallback onboarding | Anonymous registration is rate-limited and confined to public authorization code, PKCE, identity scopes, explicit consent and no roles |\n\nDynamic registration follows [RFC 7591](https://www.rfc-editor.org/rfc/rfc7591),\nbut it is **off unless advertised**. A conforming request supplies a client name,\none or more safe exact redirect URIs and the authorization-code grant. The\naccepted response echoes the effective metadata. Read that response: a\nrequested refresh grant can be omitted by policy, and no client secret is\nissued on this path.\n\n## Verify the registered client\n\nConfirm the client record shows the intended grant, roles, identity scopes,\nredirects, consent setting and token authentication method. Keep the client\nidentifier and non-secret metadata with the integration configuration; keep any\nsecret only in protected storage.\n\nThe complete secret for a confidential client is one-time credential material.\nMove it directly into the approved secrets manager and deploy it only to the\nserver-side workload that owns this client. If that handoff is lost, reissue the\nsecret through the supported lifecycle; do not ask support to recover it.\n\nComplete a controlled proof before production use:\n\n1. Load discovery metadata for the exact environment.\n2. Complete the chosen grant using the registered class and redirect behavior.\n3. Verify the resolved client, person when delegated, organization and one safe\n expected application operation.\n4. Verify one operation outside the intended roles remains refused without\n probing another customer's known identifier.\n5. Confirm logs retain client identity, outcome and correlation evidence but no\n secret, authorization code or token.\n\nRecord the client identifier, owner, environment, registration origin, grant,\nclass, roles, identity scopes, redirect inventory, consent posture, expiry or\nreview date and secrets-manager owner.`,\n },\n {\n managedPath: 'access-and-identity/oauth-authorize-delegated-access.md',\n unitRef: 'technical-documentation:unit/oauth-authorize-delegated-access',\n sourceRefs: [\n 'saas-technical-doc:engine-content/oauth-authorize-delegated-access',\n 'source:consumer-fact:access-oauth-clients',\n ],\n markdown: `# Authorize delegated access\n\nUse delegated authorization when a client acts in a person's context without\nreceiving that person's password or session.\n\n| Before you begin | Successful result |\n| --- | --- |\n| The client is registered for the advertised delegated grant, exact return destination and appropriate public/confidential method; the person knows which client is requesting access | The person can approve or deny an understandable request, the client receives a token only through its own transaction, and the resulting operation is bounded by both client and person |\n\nThe maintained client contract separates supported grants, identity claims,\napplication roles, exact redirects and consent:\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#markdown}}\n\n~~~mermaid\nsequenceDiagram\n accTitle: Authorize a client without sharing a password\n accDescr: The person starts in the client, follows the application's published authorization flow, signs in and consents when required, and the client exchanges the returned code using the registered redirect and token method.\n participant Person\n participant Client as Third-party client\n participant App as Application\n Person->>Client: Start connected task\n Client->>App: Begin published authorization flow\n App->>Person: Sign in and request consent when required\n Person->>App: Approve or deny\n App-->>Client: Return to exact registered redirect\n Client->>App: Exchange code through published token flow\n App-->>Client: Return delegated access token\n~~~\n\nThe browser journey proves the person and records their decision. The code\nexchange proves that the response belongs to the client transaction that\nstarted it. Neither step gives the client the person's reusable credential.\n\n## Explain the request before asking for approval\n\nThe authorization screen should let the person recognize:\n\n- the client asking for access and the application/environment involved;\n- the identity information requested;\n- the business task the client intends to perform;\n- the organization in which the resulting operation will occur; and\n- whether the authorization can later be reviewed or revoked.\n\nIf the client identity or request is unexpected, the safe result is **deny**.\nDenial is a valid completed decision, not an error to work around. The client\nmust not retry with broader scopes or a different identity merely to avoid it.\n\n## Keep claims and authority separate\n\n- **Identity scopes** select supported identity claims the client may request.\n- **Client roles** govern application operations.\n- **The person's membership and authority** remain part of the delegated\n decision.\n\nAdding identity scopes does not repair a refused application operation. Consent\nalso cannot make the client an administrator or grant more authority than the\nperson and client are intended to carry.\n\nFor example, allowing the client to receive an email identity claim does not\nauthorize it to administer users. Conversely, an application role accepted for\nthe client cannot make an inactive organization membership active. Diagnose\neach axis separately.\n\n## Complete and verify the flow\n\n1. Start from the client and the environment's published authorization metadata.\n2. Bind the authorization request to the browser transaction that started it.\n3. Let the person sign in using their own method.\n4. Present and preserve the consent decision when the client requires it.\n5. Return only to the exact registered redirect URI.\n6. Verify the returned issuer exactly and exchange the code using the registered\n client class and token method.\n7. Confirm the resulting client, person, organization and expected operation\n access.\n8. Confirm an operation outside the intended combined authority remains\n refused.\n\nThe following request skeleton shows the values that must remain bound to one\ntransaction. Obtain every endpoint from discovery and generate a new verifier,\nchallenge, state and nonce for each attempt.\n\n~~~text\nGET {authorization_endpoint}?\n response_type=code&\n client_id={registered_client_id}&\n redirect_uri={exact_registered_redirect_uri}&\n code_challenge={base64url_sha256_of_verifier}&\n code_challenge_method=S256&\n state={unpredictable_transaction_value}&\n nonce={unpredictable_identity_token_value}&\n resource={canonical_protected_resource_uri}&\n scope=openid%20profile\n~~~\n\nAfter the redirect, first verify \\`state\\` and the returned \\`iss\\`. Exchange the\nsingle-use code at the discovered token endpoint with the **same** redirect,\nverifier, client and resource. Public clients send their client identifier and\nno secret; confidential clients also use the registered token-endpoint\nauthentication method.\n\n~~~bash\ncurl --fail --silent --show-error \\\n --request POST \"$OAUTH_TOKEN_ENDPOINT\" \\\n --header 'content-type: application/x-www-form-urlencoded' \\\n --data-urlencode 'grant_type=authorization_code' \\\n --data-urlencode \"client_id=$OAUTH_CLIENT_ID\" \\\n --data-urlencode \"code=$OAUTH_AUTHORIZATION_CODE\" \\\n --data-urlencode \"redirect_uri=$OAUTH_REDIRECT_URI\" \\\n --data-urlencode \"code_verifier=$OAUTH_CODE_VERIFIER\" \\\n --data-urlencode \"resource=$OAUTH_RESOURCE\"\n~~~\n\nThe variables above are process-local examples, not a recommendation to place\ntokens or client secrets in shell history. Use the workload's protected secret\nand token store for production delivery.\n\nAn issuer, redirect or transaction mismatch is a security failure. Restart the\npublished flow rather than normalizing the value or reusing a code from another\nattempt.\n\n## Handle interrupted and ambiguous journeys\n\n| Symptom | Safe response |\n| --- | --- |\n| Person closes or denies the request | Preserve the decision and return to the client without issuing authority |\n| Return destination does not exactly match | Stop; correct the registered client rather than redirecting manually |\n| Issuer or transaction proof differs | Discard the response and start a fresh application-published journey |\n| Code exchange is retried after an uncertain result | Reconcile client/token state; never reuse the same code as a generic retry |\n| Token succeeds but the business operation is refused | Check person membership, client roles and exact operation contract; do not add identity scopes |\n\nAfter success, verify the original business result in the application. A token\nresponse alone does not prove that a write happened once or that the client saw\nthe intended organization.\n\nRetain environment, client identifier, organization, requested identity scopes,\nconsent outcome, approximate time, operation result and correlation evidence.\nNever retain the person's password, session cookie, authorization code, complete\ntoken, client secret or full authorization response in an ordinary ticket.`,\n },\n {\n managedPath: 'access-and-identity/oauth-operate-and-revoke.md',\n unitRef: 'technical-documentation:unit/oauth-operate-and-revoke',\n sourceRefs: [\n 'saas-technical-doc:engine-content/oauth-operate-and-revoke',\n 'source:consumer-fact:access-oauth-clients',\n ],\n markdown: `# Operate and revoke OAuth clients\n\nReview active clients as independent machine identities. Keep each client,\ncredential and delegated token associated with its owner, environment, subject\nand organization.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Identify the client, owner, environment, grant, deployed workloads, delegated users and non-secret secret prefix; know whether the change concerns client configuration, client credential or issued tokens | The intended client or token access changes, expected operation and refusal are re-proven, and unrelated integrations continue without broader authority |\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#markdown}}\n\nThe maintained registered-client lifecycle is:\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#statusMarkdown}}\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#lifecycleMarkdown}}\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#currentUsageEvidenceMarkdown}}\n\n## Change the correct lifecycle layer\n\n~~~mermaid\nflowchart TD\n accTitle: Choose the OAuth lifecycle layer that needs to change\n accDescr: The operator distinguishes the registered client contract, its confidential secret, issued delegated tokens and the person's application membership, then changes and verifies only the affected layer.\n reason{\"What must change?\"}\n reason -->|\"Grant, roles, scopes, redirects or class\"| registration[\"Review or replace client registration\"]\n reason -->|\"Confidential secret\"| credential[\"Rotate with bounded invalidation\"]\n reason -->|\"One delegated authorization\"| token[\"Use published token revocation or reauthorization\"]\n reason -->|\"Person leaves organization\"| membership[\"Suspend/remove membership or use SCIM\"]\n registration --> verify[\"Repeat complete flow and authority proof\"]\n credential --> verify\n token --> verify\n membership --> verify\n~~~\n\nThese layers are related but not interchangeable. Rotating a client secret does\nnot by itself prove that an already issued delegated token is revoked. Removing\na person's organization access is a user-administration decision, not a reason\nto silently grant the client a machine role.\n\n## Review and change a client safely\n\nAt every review, answer these questions:\n\n- Is the owner and business purpose still current?\n- Does the grant still match who authorizes the work?\n- Are application roles limited to the exact operations still used?\n- Are identity scopes limited to claims the delegated client still needs?\n- Does every redirect and post-sign-out destination still belong to this client\n and environment?\n- Does the public/confidential classification match where the client now runs?\n- Is explicit consent still appropriate for the client's trust posture?\n- Do expiry, audit evidence, resource-server activity and active deployments\n support keeping it?\n\nA changed redirect, role, grant, identity scope, consent posture or token method\nchanges the security contract. Where the management surface does not safely\nsupport that transition in place, register a replacement client and migrate\ndeliberately instead of repurposing an established identity.\n\n## Rotate a confidential client secret\n\nRotate a confidential client secret through the administration operation\nprovided for that client. Deploy and verify the new secret before the previous\none becomes invalid when a handover is intended. For suspected compromise,\ninvalidate the previous secret promptly or remove the client; do not rely on\nan open-ended regenerate operation to contain exposure.\n\nRotation reissues the secret on the same client. A future invalidation time\ncreates a bounded overlap; the default is immediate invalidation. Regeneration\ncreates an open-ended overlap until a later reissue, so it is not incident\ncontainment.\n\n1. Inventory every workload instance using the confidential client.\n2. Choose the shortest practical invalidation time and record the owner.\n3. Store the one-time replacement directly in the approved secrets manager.\n4. Deploy it everywhere and complete a safe token plus operation proof.\n5. After invalidation, confirm the replacement succeeds and the previous secret\n is refused.\n\nIf disclosure is suspected and ownership is uncertain, remove the compromised\nclient through the supported administration lifecycle and register a protected\nreplacement. Do not leave an open-ended overlap while searching for consumers.\n\n## Revoke delegated access or retire a client\n\nUse the application's published token-revocation behavior when one delegated\nauthorization should end, and require a fresh authorization journey if the\nperson later restores it. Retire an entire integration by removing its client\nregistration and every deployed secret, then confirm new token issuance fails.\nSeparately suspend or remove the person's organization membership when their\napplication access must end; SSO or OAuth revocation alone is not the membership\nlifecycle.\n\nFor a suspected incident, treat client credential exposure and issued-token\nexposure as separate questions. Contain both applicable paths and review\nactivity for the affected client, person, organization and period.\n\nToken revocation follows [RFC 7009](https://www.rfc-editor.org/rfc/rfc7009): an\nunknown or already revoked token still receives a successful response so the\nendpoint does not become a token-validity oracle. Therefore **HTTP success is\nnot the final proof**. Retry one safe protected operation with the revoked token\nand verify that it is refused, then confirm a different unaffected client still\nworks. Confidential clients must authenticate to the revocation endpoint using\ntheir registered method; a bad client secret is refused before revocation.\n\n## Diagnose OAuth failures\n\n| Symptom | Check first | Safe response |\n| --- | --- | --- |\n| Discovery or registration is unavailable | Whether the capability is advertised here | Use an enabled onboarding path; do not probe undocumented endpoints |\n| Authorization request is rejected | Client, allowed grant, exact redirect and required proof | Correct the registered client or request |\n| Consent is denied or required | Client identity, claims and intended roles | Preserve the decision and explain or correct the request |\n| Code exchange fails | Issuer, redirect, proof, client class and token method | Restart the published flow; never reuse a code |\n| Token is valid but an operation is refused | Organization, client roles and person's authority | Diagnose authorization; do not request broader identity scopes |\n| Token is invalid or revoked | Client and token lifecycle | Refresh or reauthorize only through advertised behavior |\n\n## Close the change with non-secret evidence\n\nRetain the client identifier, non-secret secret prefixes, owner, environment,\ngrant, roles, identity scopes, redirect inventory, action and approval, old-\nsecret invalidation time, affected delegated authorization, successful expected\noperation, expected refusal and correlation evidence. Never attach a client\nsecret, authorization code, access/refresh token, Authorization header or\ncomplete authorization response.`,\n },\n {\n managedPath: 'user-administration.md',\n unitRef: 'technical-documentation:unit/user-administration',\n sourceRefs: [\n 'saas-technical-doc:engine-content/user-administration',\n ],\nmarkdown: `# 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.`,\n },\n {\n managedPath: 'user-administration/manage-users-manually.md',\n unitRef: 'technical-documentation:unit/manage-users-manually',\n sourceRefs: [\n 'saas-technical-doc:engine-content/manage-users-manually',\n 'source:consumer-fact:organization-membership-administration',\n ],\n markdown: `# Manage users manually\n\nUse this path when your organization manages people directly in the application.\nIt is the right starting point when you are not using SCIM to keep this group\nof users synchronized from an identity directory. The everyday job has three\nparts: bring someone in, keep their access correct, and take access away safely\nwhen it is no longer needed.\n\n~~~mermaid\nflowchart LR\n accTitle: Manual user membership lifecycle\n accDescr: A pending invitation can be accepted or revoked. An active membership can be suspended, reactivated, or removed.\n invite[\"Invite by email\"] --> invited[\"Invitation pending\"]\n invited -->|\"Accept\"| active[\"Active\"]\n invited -->|\"Revoke\"| invitationClosed[\"Invitation closed\"]\n active -->|\"Suspend\"| suspended[\"Suspended\"]\n suspended -->|\"Reactivate\"| active\n active -->|\"Remove\"| membershipEnded[\"Membership ended\"]\n~~~\n\n## See the lifecycle at a glance\n\n{{CONSUMER_FACT:source:consumer-fact:organization-membership-administration#markdown}}\n\nThe diagram is a decision aid, not an API reference. An invitation is pending\nuntil the person accepts it. A suspension is a deliberate, reversible hold. A\nremoval ends this organization membership. Pick the action that matches what\nyou want to happen, rather than treating every change as a delete.\n\n## Work through the three jobs in order\n\n1. [Invite and onboard a user](/user-administration/invite-and-onboard-user)\n explains how to send, resend or withdraw a pending invitation, and what to\n check after the person accepts it.\n2. [Change a user's access](/user-administration/change-user-access) explains\n how to review and adjust roles or organization-unit assignments without\n granting broad access by accident.\n3. [Suspend or remove a user](/user-administration/suspend-or-remove-user)\n explains the difference between a temporary hold, cancelling an unaccepted\n invitation, and permanently removing a membership.\n\n## Know when not to manage manually\n\nSingle sign-on changes how a person proves who they are when they sign in. It\ndoes not, by itself, decide who receives a membership, role or offboarding\naction. SCIM is different: it lets an identity directory own the lifecycle for\nthe people it manages. If your directory is the source of truth for this user,\nuse [SCIM provisioning](/user-administration/scim-provisioning) rather than\nmaking a competing manual change.\n\n## Check the result every time\n\nAfter a meaningful change, confirm the membership state and effective role in\nthe user-management screen. For a sensitive change, also review the audit\nrecord for the person affected, the administrator who made the change, the\norganization, and the outcome. Do not paste invitation links, reset material or\ncredentials into tickets or audit notes.`,\n },\n {\n managedPath: 'user-administration/invite-and-onboard-user.md',\n unitRef: 'technical-documentation:unit/invite-and-onboard-user',\n sourceRefs: [\n 'saas-technical-doc:engine-content/invite-and-onboard-user',\n ],\n 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.`,\n },\n {\n managedPath: 'user-administration/roles-and-permissions.md',\n unitRef: 'technical-documentation:unit/organization-roles',\n sourceRefs: [\n 'saas-technical-doc:engine-content/organization-roles',\n 'source:companion-projection:application-administration',\n 'source:companion-projection:organization-roles',\n 'source:consumer-fact:organization-membership-administration',\n ],\n 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.`,\n },\n {\n managedPath: 'user-administration/change-user-access.md',\n unitRef: 'technical-documentation:unit/change-user-access',\n sourceRefs: [\n 'saas-technical-doc:engine-content/change-user-access',\n ],\n 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.`,\n },\n {\n managedPath: 'user-administration/manage-organization-units.md',\n unitRef: 'technical-documentation:unit/manage-organization-units',\n sourceRefs: [\n 'saas-technical-doc:engine-content/manage-organization-units',\n 'source:companion-projection:application-administration',\n 'source:companion-projection:organization-unit-aware-resources',\n 'source:consumer-fact:organization-units',\n ],\n 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.`,\n },\n {\n managedPath: 'user-administration/design-organization-unit-hierarchy.md',\n unitRef: 'technical-documentation:unit/design-organization-unit-hierarchy',\n sourceRefs: ['saas-technical-doc:engine-content/design-organization-unit-hierarchy'],\n markdown: `# Design the organization-unit hierarchy\n\nBuild the smallest hierarchy that represents durable access boundaries. This\npage is for the administrator who understands how the organization is divided\nand can name which application information each part should control.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | An organization owner or administrator working with the business owners of each proposed access boundary |\n| **Where the design applies** | One organization and the application information that can be narrowed inside it |\n| **Before you begin** | Name the information or actions each unit must control, the owner of that boundary and the intended inheritance behavior |\n| **Successful result** | A small, explainable, cycle-free hierarchy exists before member assignments are added, with broad inheritance used only where it is intentional |\n\nUse the application’s organization-unit administration screen when one is\navailable. Otherwise, follow the organization-unit API operations linked from\nthis page. Do not edit the internal hierarchy path directly; create and move\nunits through the published operations.\n\n## Start from access, not the org chart\n\nAsk these questions for every proposed unit:\n\n- **What information or action will be narrowed by this unit?**\n- **Who decides who belongs here?**\n- **Should a role at this unit reach every child below it?**\n- **Will this structure remain understandable after the next reorganization?**\n\nIf the only answer is reporting, presentation or a temporary project label,\nkeep that information as ordinary business data instead of an authorization\nboundary.\n\n## Understand downward inheritance\n\n~~~mermaid\nflowchart TD\n accTitle: Organization-unit inheritance moves downward\n accDescr: A direct role at Sales reaches EMEA and France only when Sales passes access to descendants. A role at France never travels upward.\n manager[\"Sales manager\"] -->|\"Direct assignment\"| sales[\"Sales\"]\n sales --> emea[\"EMEA\"]\n emea --> france[\"France\"]\n manager -.->|\"Inherited when enabled\"| emea\n manager -.->|\"Inherited when enabled\"| france\n~~~\n\nInheritance moves from a unit to its descendants, never from a child to its\nparent. A root assignment with downward inheritance can reach the entire tree,\nso review it with the same care as a broad organization role.\n\n## Create the hierarchy\n\n1. Create only the top-level units that represent real access boundaries.\n2. Add a child when its access responsibility is meaningfully contained by the\n parent.\n3. Choose the descriptive type—company, division, department, team, subteam,\n project group, geographic, functional or custom. **The type itself grants no\n permission.**\n4. Give the unit a clear human name. Add a short code only when another process\n needs a stable sibling-level identifier.\n5. Enable downward inheritance only when parent responsibility should cover\n every current and future descendant.\n6. Review the tree before assigning a population.\n\nThe application maintains the internal hierarchy path when a unit is created or\nmoved. Do not expose or edit that path as a business identifier.\n\n## Review the design before assignment\n\n- Could one parent assignment unintentionally cover unrelated teams?\n- Will moving a branch later change inherited access for many people?\n- Can an administrator explain why every unit exists in access terms?\n- Is a directory department value expected to map to this exact unit?\n\nWhen the structure is ready, continue with [Assign organization-unit\naccess](/user-administration/assign-organization-unit-access).`,\n },\n {\n managedPath: 'user-administration/assign-organization-unit-access.md',\n unitRef: 'technical-documentation:unit/assign-organization-unit-access',\n sourceRefs: [\n 'saas-technical-doc:engine-content/assign-organization-unit-access',\n 'source:companion-projection:organization-unit-aware-resources',\n ],\n markdown: `# Assign organization-unit access\n\nAssign a person to a unit when they need access in one part of the organization\nwithout receiving the same authority everywhere. The person must already have\nan **Active** membership in the organization.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | An organization owner or administrator allowed to grant the selected role |\n| **Where the change applies** | One organization unit and, only when inheritance is enabled, its descendant units |\n| **Before you begin** | Confirm an active membership, the unit hierarchy, the role, inheritance and at least one application resource that is unit-aware |\n| **Successful result** | The person can perform the approved action in the intended unit while the same action remains unavailable in an unrelated unit |\n\nAn application may provide a dedicated organization-unit administration\nscreen. When it does not, use the organization-unit membership API operations\nlinked from this page. Do not assume that the **Members** screen exposes every\nunit operation: UI availability is an application choice, while the published\nAPI reference is the exact automation contract.\n\n> **A unit assignment is an additional, narrowed grant.** It does not replace\n> the person’s organization role and cannot reduce access already granted\n> organization-wide.\n\n~~~mermaid\nflowchart LR\n accTitle: Evaluate organization-wide and unit access\n accDescr: An organization-wide role can allow the operation first. Otherwise, the application checks a sufficient role on the record's unit or an inheriting ancestor.\n request[\"Person requests an operation\"] --> org{\"Organization-wide role allows it?\"}\n org -->|\"Yes\"| allow[\"Allow\"]\n org -->|\"No\"| narrowed{\"Resource is unit-aware?\"}\n narrowed -->|\"No\"| deny[\"Refuse\"]\n narrowed -->|\"Yes\"| unit{\"Sufficient direct or inherited unit role?\"}\n unit -->|\"Yes\"| allow\n unit -->|\"No\"| deny\n~~~\n\n## Make the assignment\n\n1. Confirm the intended person and organization membership.\n2. Select the unit where their responsibility begins.\n3. Choose one role for that member in that unit.\n4. Review the unit’s inheritance setting and every descendant it can cover.\n5. Save the assignment and inspect the resulting membership and unit.\n\nA member can belong to several units, but holds one role per unit. The\nadministrator can grant only roles inside their own organization-wide\nassignment ceiling. Holding a powerful role in one unit does not raise that\nceiling.\n\n## Prove both the access and its boundary\n\n{{APPLICATION_ORGANIZATION_UNIT_RESOURCES}}\n\nUse the person’s own account and choose a resource that the application\nexplicitly narrows by unit:\n\n- verify one approved action on a record in the assigned unit;\n- verify the same action on a descendant when inheritance is enabled;\n- verify that an unrelated sibling unit remains unavailable; and\n- verify that an authority-bearing area such as membership or API-key\n administration has not become available because of the unit role.\n\nSuccessful access alone is not enough evidence. The refused sibling action is\nwhat proves that the grant is narrow.\n\n### Why did the assignment not change anything?\n\nThe selected resource may not be unit-aware, the record may name another unit,\nthe assigned role may not satisfy the operation, the membership may not be\nactive, or inheritance may stop before the record’s unit. Check those facts\nbefore granting a broader organization role.`,\n },\n {\n managedPath: 'user-administration/operate-organization-units.md',\n unitRef: 'technical-documentation:unit/operate-organization-units',\n sourceRefs: ['saas-technical-doc:engine-content/operate-organization-units'],\n markdown: `# Operate the organization-unit hierarchy\n\nChanges to a live hierarchy can change inherited access for an entire branch.\nReview the affected people and unit-aware information before you move, archive,\nrestore or delete a unit.\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 the affected access boundaries |\n| **Where the change applies** | The selected unit, its descendants and the people whose inherited reach can change |\n| **Before you begin** | Export or inspect the branch, direct assignments, inherited assignments and representative unit-aware records |\n| **Successful result** | The hierarchy reaches the intended state, affected access is re-tested, unrelated units remain isolated and the audit record explains the change |\n\nUse the application’s organization-unit administration screen when it exposes\nthe required action. Otherwise, use the organization-unit API operations linked\nfrom this page; archive, restore, move and delete are distinct operations and\nmust not be simulated by editing fields.\n\n## Understand each operation\n\n| Action | What the application changes | What it does **not** do |\n| --- | --- | --- |\n| Move | Moves the unit and all descendants, then rewrites their maintained hierarchy paths | It does not preserve the former inherited reach |\n| Archive | Marks the selected unit archived | It does not revoke assignments, hide records or automatically archive descendants |\n| Restore | Returns an archived unit when its parent chain is available | It does not restore an archived ancestor first |\n| Delete | Removes an empty leaf unit | It does not silently detach child units or member assignments |\n\n> **Status is not revocation.** Archiving, suspending or deactivating a unit\n> records its operational state, but existing assignments and the records they\n> cover remain. Remove or change assignments when access must end.\n\n## Move a branch safely\n\n1. List the unit, all descendants and every direct member assignment.\n2. Compare inherited access at the old and proposed parent.\n3. Identify people who will gain or lose reach after the move.\n4. Move the branch only after the affected access owners approve the result.\n5. Re-test an approved and an unapproved unit-aware record.\n\nMoving a unit into itself or one of its descendants is refused because it would\ncreate a cycle.\n\n## Archive, restore or delete safely\n\n- Before archiving, decide whether assignments should remain for history or be\n removed to end access.\n- Restore the parent chain before restoring a child beneath an archived parent.\n- Before deletion, move or remove every child and remove every member assignment.\n Only an empty leaf can be deleted.\n- When SCIM owns the unit assignment, change the directory mapping rather than\n recreating a competing manual assignment.\n\nAfter every structural change, review the audit record and verify the practical\nresult with a representative member’s own account.`,\n },\n {\n managedPath: 'user-administration/suspend-or-remove-user.md',\n unitRef: 'technical-documentation:unit/suspend-or-remove-user',\n sourceRefs: [\n 'saas-technical-doc:engine-content/suspend-or-remove-user',\n ],\n 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.`,\n },\n {\n managedPath: 'user-administration/review-users-and-access.md',\n unitRef: 'technical-documentation:unit/review-users-and-access',\n sourceRefs: [\n 'saas-technical-doc:engine-content/review-users-and-access',\n ],\n 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.`,\n },\n {\n managedPath: 'user-administration/troubleshoot-user-access.md',\n unitRef: 'technical-documentation:unit/troubleshoot-user-access',\n sourceRefs: ['saas-technical-doc:engine-content/troubleshoot-user-access'],\n markdown: `# Troubleshoot user access\n\nStart with what the person experiences, then check identity, organization,\nmembership and role in that order. Do not grant a broader role merely because\nit makes the symptom disappear: that hides the cause and can create a second\naccess problem.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | The person experiencing the problem and an administrator who can inspect the relevant identity and membership state |\n| **Where the investigation applies** | The exact organization, resource and action where the symptom occurs |\n| **Before you begin** | Record the symptom, time, active organization and non-secret error details; never request a password, factor code or token |\n| **Successful result** | The failing decision is identified at the identity, organization, membership, role, unit or operation layer and corrected without broadening unrelated access |\n\n~~~mermaid\nflowchart TD\n accTitle: Diagnose user access in the order decisions are made\n accDescr: First prove the person can authenticate, then confirm the active organization and membership, then inspect organization and unit roles, and finally the exact requested action.\n symptom[\"Person reports an access problem\"] --> auth{\"Can they sign in?\"}\n auth -->|\"No\"| signin[\"Check sign-in method, factor and SSO\"]\n auth -->|\"Yes\"| org{\"Correct active organization?\"}\n org -->|\"No\"| switch[\"Select the intended organization\"]\n org -->|\"Yes\"| membership{\"Membership Active?\"}\n membership -->|\"No\"| lifecycle[\"Resolve invitation, suspension or directory state\"]\n membership -->|\"Yes\"| role{\"Role and unit assignment sufficient?\"}\n role -->|\"No\"| access[\"Review the intended least-privileged assignment\"]\n role -->|\"Yes\"| operation[\"Check the exact action and resource scope\"]\n~~~\n\n## Start from the symptom\n\n| The person says… | Check first | Safe next action |\n| --- | --- | --- |\n| “I cannot sign in” | Offered sign-in method, SSO routing, factor challenge and account state | Follow the sign-in or identity-provider recovery path; do not change a role yet |\n| “I did not receive the invitation” | Intended email, membership state and whether an earlier invitation exists | Correct or resend the invitation journey without creating a duplicate identity |\n| “I can sign in but see the wrong organization” | Active organization selection and membership in the intended organization | Switch to the intended organization; roles do not copy between memberships |\n| “I can open the application but cannot do this task” | Exact task, organization role, unit-aware resource and unit assignment | Compare the least-privileged role with the exact operation; test an approved and refused boundary |\n| “My access is paused” | Suspended or inactive membership, directory ownership and recovery condition | Reactivate only through the owning lifecycle path and preserve owner continuity |\n| “The directory change did not appear” | SCIM response, exact operation, mapping value and resulting resource state | Correct the directory/mapping or use a supported full reconciliation; do not create a competing manual state |\n\n## If the person cannot sign in\n\nConfirm the sign-in method actually offered for this person and organization.\nFor SSO, verify the identity-provider connection and the person’s directory\nassignment. A successful SSO assertion still needs a usable application user\nand organization membership. For a required second factor, use the published\nfactor-recovery journey; never ask the person to share a code or another\nperson’s session.\n\n## If sign-in works but access is wrong\n\n1. Confirm the active organization shown to the person.\n2. Confirm the membership is **Active** in that same organization.\n3. Compare organization roles with [Roles and\n permissions](/user-administration/roles-and-permissions).\n4. If the resource is unit-aware, inspect the record’s unit, the person’s direct\n assignment and any downward inheritance.\n5. Test with the person’s own account: one intended action and one nearby action\n that should remain refused.\n\nAn administrator’s successful test is not evidence that the person’s access is\ncorrect. Likewise, an API denial should be diagnosed from its credential and\noperation contract instead of repaired with a more powerful credential.\n\n## If a lifecycle change is refused\n\nCheck whether the action would leave the organization without a usable owner,\nwhether SCIM owns the membership, or whether the requested state transition is\nvalid from its current state. Establish another active owner before an owner\nreduction or removal. Make directory-owned changes in the directory and inspect\nthe resulting membership before retrying manually.\n\nWhen you escalate the issue, include the organization, affected membership\nstate, intended task, timestamp and non-secret error details. Remove tokens,\ncredentials and unnecessary personal data.`,\n },\n {\n managedPath: 'user-administration/scim-provisioning.md',\n unitRef: 'technical-documentation:unit/scim',\n sourceRefs: [\n 'saas-technical-doc:engine-content/scim',\n 'source:consumer-fact:organization-scim-provisioning',\n ],\n markdown: `# Provision users with SCIM\n\nSCIM lets an identity directory maintain a defined population of users and\norganization memberships. Choose it when your directory should own repeatable\njoiner, mover and leaver changes. The application supports **SCIM Users**, not\nSCIM Groups; a directory \\`department\\` can be mapped to one existing\norganization unit.\n\n> **SCIM provisions access; it does not sign people in.** Configure and prove\n> single sign-on separately. A directory-managed person needs both a correctly\n> provisioned membership and a working enterprise sign-in path.\n\n~~~mermaid\nflowchart LR\n accTitle: Adopt SCIM in four controlled stages\n accDescr: Configure the connection, map profile and unit data, validate with a small population, then operate and troubleshoot the live integration.\n configure[\"Configure lifecycle and credential\"] --> map[\"Map profile and unit data\"]\n map --> validate[\"Validate and roll out\"]\n validate --> operate[\"Operate and troubleshoot\"]\n~~~\n\n## How a directory change becomes application access\n\nProvisioning is not a single switch. A directory assignment passes through\nseveral independent decisions before a person can use the application:\n\n~~~mermaid\nsequenceDiagram\n accTitle: From directory assignment to usable application access\n accDescr: A directory administrator assigns a person, the identity provider sends a SCIM User request, the application validates the organization token and profile, maintains the identity and membership, optionally reconciles a mapped organization unit on supported operations, and responds. The person later signs in through a separate authentication journey and current membership and role determine access.\n actor Admin as Directory administrator\n participant Directory as Identity directory\n participant SCIM as Application SCIM service\n participant Access as Identity and membership\n participant Units as Organization units\n actor Person as Person\n Admin->>Directory: Assign person to the application\n Directory->>SCIM: Send SCIM User operation\n SCIM->>SCIM: Authenticate token and validate payload\n SCIM->>Access: Create or update identity and membership\n opt Department mapping on a supported operation\n SCIM->>Units: Reconcile mapped unit assignment\n end\n SCIM-->>Directory: Return SCIM result\n Person->>Access: Sign in through the configured method\n Access-->>Person: Evaluate current membership and role\n~~~\n\nThis journey separates six decisions that are often confused during a rollout:\n\n| Decision | Question the owners must answer |\n| --- | --- |\n| Provisioned population | Which directory assignment or group decides who is sent to the application? |\n| Identity matching | Which stable directory value identifies the same person after an email or name change? |\n| Initial access | Which non-administrative organization role should a newly provisioned person receive? |\n| Leaver behavior | What should happen to the application user and membership when the directory sends \\`active:false\\`? |\n| Unit authority | Should \\`department\\` merely describe the person, or authoritatively add and remove organization-unit access? |\n| Authentication | Which sign-in or SSO method will the person use after provisioning succeeds? |\n\n> **A successful SCIM response proves provisioning, not usable access.** Verify\n> the resulting membership, role and unit assignments, then ask the pilot person\n> to complete the separate sign-in journey.\n\n## Choose the stage you are working on\n\n| Your goal | Continue with |\n| --- | --- |\n| Understand the supported SCIM profile, payloads and operation behavior | [SCIM protocol and payload reference](/user-administration/scim-protocol-and-payloads) |\n| Decide lifecycle defaults and connect the directory | [Configure SCIM provisioning](/user-administration/scim-configure) |\n| Connect Microsoft Entra ID or a synchronized Active Directory population | [Connect Microsoft Entra ID](/user-administration/scim-microsoft-entra) |\n| Connect an Okta organization | [Connect Okta](/user-administration/scim-okta) |\n| Start from Active Directory Domain Services or another LDAP directory | [Connect an LDAP or Active Directory source](/user-administration/scim-ldap-and-active-directory) |\n| Map names, email and department-owned unit access | [Map SCIM profiles and organization units](/user-administration/scim-map-profile-and-units) |\n| Prove behavior with controlled users before broad enablement | [Validate and roll out SCIM](/user-administration/scim-validate-and-roll-out) |\n| Rotate credentials, investigate errors or recover a person | [Operate and troubleshoot SCIM](/user-administration/scim-operate-and-troubleshoot) |\n\n{{CONSUMER_FACT:source:consumer-fact:organization-scim-provisioning#markdown}}\n\n## Decide whether SCIM fits\n\nUse SCIM only when the directory will be the source of truth for the population,\nenterprise sign-in already works, and named owners can respond to provisioning\nfailures and credential changes. Keep people deliberately outside the directory\non the manual path. Do not let SCIM and an administrator compete to manage the\nsame membership or unit assignment.`,\n },\n {\n managedPath: 'user-administration/scim-protocol-and-payloads.md',\n unitRef: 'technical-documentation:unit/scim-protocol-and-payloads',\n sourceRefs: [\n 'saas-technical-doc:engine-content/scim-protocol-and-payloads',\n 'source:consumer-fact:organization-scim-provisioning',\n ],\n 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.`,\n },\n {\n managedPath: 'user-administration/scim-configure.md',\n unitRef: 'technical-documentation:unit/scim-configure',\n sourceRefs: [\n 'saas-technical-doc:engine-content/scim-configure',\n 'source:consumer-fact:organization-scim-provisioning',\n ],\n 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.`,\n },\n {\n managedPath: 'user-administration/scim-microsoft-entra.md',\n unitRef: 'technical-documentation:unit/scim-microsoft-entra',\n sourceRefs: ['saas-technical-doc:engine-content/scim-microsoft-entra'],\n markdown: `# Provision users from Microsoft Entra ID\n\nConnect one Microsoft Entra enterprise application to one application\norganization. Entra decides which assigned people should exist; SCIM creates or\nupdates their application identities and organization memberships. **This\nconnection provisions access—it does not configure how those people sign in.**\nConfigure and test single sign-on separately.\n\n~~~mermaid\nflowchart LR\n directory[\"Active Directory or another HR source\"] --> entra[\"Microsoft Entra ID\"]\n entra -->|\"SCIM 2.0 over HTTPS\"| endpoint[\"Application SCIM endpoint\"]\n endpoint --> identity[\"User profile\"]\n endpoint --> membership[\"Organization membership and role\"]\n endpoint -. \"department on supported operations\" .-> unit[\"Organization-unit assignments\"]\n~~~\n\nIf your source is on-premises Active Directory Domain Services, synchronize it\nto Entra first. The application does not accept LDAP traffic at its SCIM\nendpoint.\n\n## Before you configure Entra\n\n- Create a non-production organization or select a small pilot organization.\n- Verify that the pilot person can sign in by the organization’s intended\n authentication method.\n- Create the application’s SCIM provisioning configuration and a **dedicated\n token for this Entra connection**.\n- Choose a non-administrative default role. Do not provision broad access merely\n to make the first test pass.\n- Decide whether Entra’s \\`department\\` value should control organization-unit\n access. Leave unit mapping off until the operation behavior below is proven.\n\n## Create the enterprise application\n\n1. In the Microsoft Entra admin center, open **Enterprise applications** and\n create or select the application used for provisioning.\n2. Open **Provisioning**, choose an automatic provisioning mode, and start a new\n configuration.\n3. Set **Tenant URL** to the application’s public API origin followed by:\n\n ~~~text\n /api/v1/scim/v2\n ~~~\n\n4. Set **Secret Token** to the plaintext SCIM token returned by the application.\n It is a bearer credential; store it in Entra and your approved secret-recovery\n process, not in a ticket or documentation screenshot.\n5. Run **Test Connection**.\n\nEntra’s connection test queries a randomly generated, non-existent user. A\ncorrect empty result is HTTP 200 with a SCIM \\`ListResponse\\` and zero resources.\nThat proves URL, TLS, token and basic query compatibility. **It does not prove\nrole assignment, deactivation, department changes or sign-in.**\n\n## Configure the user mappings\n\nKeep the first mapping small and observable:\n\n| Entra source | SCIM target | Decision to verify |\n| --- | --- | --- |\n| \\`userPrincipalName\\` or a verified mail attribute | \\`userName\\` | Must be stable and unique for the person |\n| \\`mail\\` | \\`emails[type eq \"work\"].value\\` | Must resolve to an admitted organization domain when domain restrictions exist |\n| \\`givenName\\` | \\`name.givenName\\` | Check accents and empty values |\n| \\`surname\\` | \\`name.familyName\\` | Check the real payload, not the portal preview alone |\n| \\`displayName\\` | \\`displayName\\` | Decide which system owns later changes |\n| Account-enabled expression | \\`active\\` | Test disable and re-enable as separate access events |\n| \\`department\\` | Enterprise User \\`department\\` | Enable only if department is an access-control authority |\n\nThis application currently exposes **Users**, not SCIM **Groups**. Disable group\nobject provisioning and Push Groups-style expectations. Entra groups may still\nbe useful on the Entra side to decide who is assigned to the enterprise\napplication, but they are not imported as application groups.\n\n## Treat department-to-unit mapping as a controlled rollout\n\nThe application reconciles organization units on direct \\`POST /Users\\` and full\n\\`PUT /Users/{id}\\` operations. It does **not** currently reconcile units on\n\\`PATCH\\` or \\`Bulk\\`. Entra can use PATCH for attribute changes, so a successful\nprofile update does not prove that moving a person between departments removed\ntheir former unit access.\n\nBefore making department authoritative:\n\n1. Map one test department to one existing organization unit.\n2. Use **Provision on demand** for a pilot person and record the SCIM operation\n visible in the application/provider evidence.\n3. Change the person’s department.\n4. Confirm both the new assignment and removal of the old assignment in the\n application—not only a successful Entra job.\n5. If Entra sends PATCH, leave automatic unit reconciliation disabled until the\n application supports that operation or your integration deliberately sends a\n tested full replacement.\n\n## Roll out and operate\n\n- Start with **Sync only assigned users and groups** and assign a small pilot\n population. This scopes Entra’s source population; it does not add SCIM Group\n support to the application.\n- Verify in the application: user profile, membership status, organization role,\n unit assignments and sign-in.\n- Review Entra provisioning logs for the request and response associated with\n each pilot person. Preserve provider job identifiers, not bearer tokens.\n- Configure provisioning-failure notifications and review Microsoft’s\n accidental-deletion prevention before broad assignment.\n- Rotate a token as an immediate credential cutover: update Entra promptly and\n run the connection test again.\n\n## Microsoft documentation to keep with the runbook\n\n- Use Microsoft’s [provision users and groups with SCIM](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/use-scim-to-provision-users-and-groups)\n guide for current Entra portal controls, attribute mappings, test connection\n and provisioning behavior. The application-specific limits on this page\n still take precedence over generic provider capabilities.\n- Use [how Microsoft Entra provisioning works](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/how-provisioning-works)\n to understand the provider’s synchronization cycle and the path from a\n connected source such as Active Directory to an enterprise application.\n\nRecord the reviewed provider-documentation date in the production runbook;\nportal labels and provider behavior can change independently of the application.`,\n },\n {\n managedPath: 'user-administration/scim-okta.md',\n unitRef: 'technical-documentation:unit/scim-okta',\n sourceRefs: ['saas-technical-doc:engine-content/scim-okta'],\n markdown: `# Provision users from Okta\n\nUse an Okta SCIM 2.0 application to create, update and deactivate people in one\napplication organization. The Okta assignment determines who is provisioned;\nthe application’s SCIM configuration determines the role and lifecycle effects.\nSign-on configuration remains a separate SSO decision.\n\n~~~mermaid\nflowchart LR\n accTitle: Keep Okta assignment, provisioning and application access distinct\n accDescr: An Okta administrator assigns a person or population to the Okta application. Okta sends SCIM User operations to the application. The application maintains the user profile and organization membership, applies the configured default role, and optionally reconciles a mapped department on supported operations. The person signs in through a separately configured method.\n source[\"Okta user and assignment\"] --> provision[\"Okta provisioning connector\"]\n provision -->|\"SCIM User operations\"| endpoint[\"Application SCIM endpoint\"]\n endpoint --> profile[\"User profile\"]\n endpoint --> membership[\"Organization membership and default role\"]\n endpoint -. \"mapped department on supported operations\" .-> units[\"Organization-unit access\"]\n signin[\"Separate sign-in or SSO journey\"] --> membership\n~~~\n\nThe Okta assignment defines the population. It does not choose the\napplication role, import an Okta group as an application group, or prove that\nthe person can sign in. Verify those outcomes separately during the pilot.\n\n## Choose the correct Okta integration shape\n\nFor a private connection, create or use a **SCIM 2.0 Test App (Header Auth)** or\nanother Okta application whose provisioning connector lets you supply a SCIM\nbase URL and bearer token. If the application later has a reviewed Okta\nIntegration Network entry, follow that entry instead of duplicating it.\n\nThe application accepts SCIM **User** resources. It does not currently expose a\nSCIM Group resource, so do not enable Push Groups or depend on group-object\nimports. An Okta group can still control which users are assigned to the Okta\napplication.\n\n## Connect Okta\n\n1. In the Okta Admin Console, open the application’s **Provisioning** settings.\n2. Enable API integration and choose bearer/header authentication.\n3. Set the SCIM connector base URL to the application’s public API origin plus\n \\`/api/v1/scim/v2\\`.\n4. Paste a dedicated application-issued SCIM token into the API token field.\n5. Run **Test API Credentials**.\n\nThe credential test is a transport and authorization test. Complete a pilot\ncreate, update and deactivate before treating the connection as ready.\n\n## Configure provisioning actions\n\nEnable only the actions you are prepared to verify:\n\n| Okta **To App** action | Application effect to test |\n| --- | --- |\n| Create Users | Creates or links the user, then creates the organization membership with the configured default role |\n| Update User Attributes | Updates maintained profile values; inspect whether Okta used PUT or PATCH |\n| Deactivate Users | Normally sends \\`active:false\\`; verify the application user and organization membership consequences |\n| Sync Password | **Keep disabled.** The SCIM service does not accept password changes |\n\nUse a stable, unique Okta attribute for \\`userName\\`. Map the work email, given\nname, family name and display name explicitly. When verified-domain restrictions\nexist, ensure the resolved work email is admitted before the pilot.\n\n### Department and organization units\n\nMap Okta’s department to the SCIM Enterprise User extension only when it is\nauthoritative enough to change access. Then map exact department values to\nexisting application organization units.\n\n> **Operation limitation:** organization-unit reconciliation currently runs for\n> direct user creation and full replacement. It does not run for PATCH or Bulk.\n> Capture the operation Okta sends for a department change and prove that the\n> old unit assignment is removed before production rollout.\n\n## Prove one complete lifecycle\n\n1. Assign one pilot user to the Okta application.\n2. Confirm the person appears in the intended application organization with the\n approved role—not an administrator role.\n3. Change one mapped profile value and confirm it in the application.\n4. If unit mapping is enabled, move the pilot between two mapped departments and\n confirm both addition and removal.\n5. Unassign or deactivate the pilot. Confirm the user and membership state in\n the application and verify the effect on any other organization membership.\n6. Reassign the pilot. Confirm that the organization membership is usable again;\n a globally active user alone is not sufficient proof.\n\nUse Okta’s **System Log** and provisioning task details to correlate failures.\nRecord time, Okta user/application identifiers, SCIM operation, HTTP status,\nredacted SCIM error and resulting application state. Never record the API token.\n\n## Okta documentation to keep with the runbook\n\n- Use Okta’s [connect a private SCIM integration](https://developer.okta.com/docs/guides/scim-provisioning-integration-connect/main/)\n guide for current Admin Console fields and connector setup.\n- Use the [Okta SCIM protocol reference](https://developer.okta.com/docs/api/openapi/okta-scim/guides)\n when diagnosing the operation, filter, payload or response Okta expects.\n- Use [Understanding SCIM](https://developer.okta.com/docs/concepts/scim/)\n to align directory and application owners on assignment, provisioning and\n deprovisioning responsibilities.\n\nKeep the application profile on this page beside those provider references:\nOkta’s support for a feature does not mean this application exposes it.`,\n },\n {\n managedPath: 'user-administration/scim-ldap-and-active-directory.md',\n unitRef: 'technical-documentation:unit/scim-ldap-and-active-directory',\n sourceRefs: ['saas-technical-doc:engine-content/scim-ldap-and-active-directory'],\n markdown: `# Provision from LDAP or Active Directory\n\nLDAP and SCIM solve different parts of directory integration. LDAP is a\ndirectory access protocol; this application exposes an HTTPS SCIM 2.0 service.\n**Do not send LDAP requests to the SCIM URL and do not expose an internal LDAP\nserver to the application.** Place a provisioning service or controlled bridge\nbetween the source directory and SCIM.\n\n## Choose an architecture\n\n~~~mermaid\nflowchart LR\n subgraph source[\"Directory source\"]\n ad[\"Active Directory Domain Services\"]\n ldap[\"LDAP directory\"]\n end\n ad --> entra[\"Microsoft Entra synchronization and provisioning\"]\n ldap --> bridge[\"Managed provisioning agent or owned bridge\"]\n entra -->|\"HTTPS + SCIM 2.0\"| app[\"Application SCIM Users service\"]\n bridge -->|\"HTTPS + SCIM 2.0\"| app\n~~~\n\n| Source situation | Practical route |\n| --- | --- |\n| Active Directory identities already synchronized to Microsoft Entra ID | Configure Entra enterprise-application provisioning and let Entra emit SCIM |\n| LDAP identities governed through Okta | Use the supported Okta directory/agent path, then configure Okta’s application provisioning connector |\n| Another LDAP directory with a supported identity-governance product | Use that product’s SCIM connector after validating this application’s implemented profile |\n| No provider can emit the required SCIM profile | Build and operate a narrow LDAP-to-SCIM bridge with explicit ownership, tests and monitoring |\n\nThe last option is software you own. It should not be treated as a configuration\nscript: it becomes an identity lifecycle and access-control component.\n\n## Define the attribute transformation\n\nRead the source directory using its documented schema, then emit a standards-\ncompliant SCIM User. A common starting point is:\n\n| LDAP / Active Directory value | SCIM value | Required decision |\n| --- | --- | --- |\n| \\`userPrincipalName\\` or approved login attribute | \\`userName\\` | Stable uniqueness and rename policy |\n| \\`mail\\` | \\`emails[type eq \"work\"].value\\` | Missing email and verified-domain policy |\n| \\`givenName\\` | \\`name.givenName\\` | Empty and internationalized values |\n| \\`sn\\` | \\`name.familyName\\` | Empty-value behavior |\n| \\`displayName\\` | \\`displayName\\` | Which system owns later edits |\n| \\`department\\` | Enterprise User \\`department\\` | Whether it is authoritative for unit access |\n| Disabled-account state | \\`active:false\\` | Global user and membership deactivation consequence |\n\nThese are mapping decisions, not guaranteed attributes in every LDAP schema.\nInspect representative entries and document the source object classes,\nattribute ownership and null behavior.\n\n### Example SCIM document emitted by a bridge\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\": \"4fd9cc8d-7f42-4ab4-9036-07c94b2ac663\",\n \"userName\": \"alex.morgan@example.com\",\n \"active\": true,\n \"name\": {\n \"givenName\": \"Alex\",\n \"familyName\": \"Morgan\"\n },\n \"emails\": [\n { \"type\": \"work\", \"primary\": true, \"value\": \"alex.morgan@example.com\" }\n ],\n \"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User\": {\n \"department\": \"Engineering\"\n }\n}\n~~~\n\n## Requirements for an owned bridge\n\nA production bridge needs all of the following:\n\n- TLS validation for LDAP and HTTPS, and secrets held in an approved vault;\n- a durable relationship between source identifiers, SCIM \\`externalId\\` and the\n application’s returned SCIM resource identifier;\n- deterministic create-versus-update matching and a documented rename policy;\n- bounded pagination, checkpoints, retry with backoff and idempotent replay;\n- explicit handling for disable, delete, restore and a person missing from a\n source query;\n- redacted operational evidence linking one source change to one SCIM response;\n- reconciliation that detects drift rather than repeatedly overwriting it;\n- a tested response to rate limiting, token rotation and partial batch failure.\n\nDo not use Bulk for a first implementation merely for speed. The application\nsupports a bounded Bulk request, but Bulk currently does not perform\norganization-unit reconciliation. Start with observable individual operations.\n\n## Validate before production\n\nRun a positive and negative lifecycle: create an admitted user, reject a user\nfrom a disallowed domain when restrictions exist, update the profile, change a\ndepartment, disable the source account and restore it. At every step compare\nthe directory state, emitted SCIM document, HTTP result, application user,\nmembership, role and unit assignments.\n\n## Standards and provider documentation\n\n- [RFC 4511](https://www.rfc-editor.org/rfc/rfc4511.html) defines LDAP’s\n protocol. It explains the source-side boundary; it does not make an LDAP\n directory a SCIM provider.\n- [RFC 7643](https://www.rfc-editor.org/rfc/rfc7643.html) and\n [RFC 7644](https://www.rfc-editor.org/rfc/rfc7644.html) define the SCIM\n resource and protocol boundaries the bridge must emit.\n- Microsoft documents the path from connected systems to SCIM in\n [How application provisioning works](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/how-provisioning-works).\n- For an Okta-governed directory, compare the bridge design with Okta’s\n [private SCIM integration guide](https://developer.okta.com/docs/guides/scim-provisioning-integration-connect/main/)\n and [SCIM protocol reference](https://developer.okta.com/docs/api/openapi/okta-scim/guides).\n\nThese references define the systems on either side of the bridge. The bridge’s\nmatching, checkpoint, retry and reconciliation behavior remains an operated\ncomponent your organization must specify and test.`,\n },\n {\n managedPath: 'user-administration/scim-map-profile-and-units.md',\n unitRef: 'technical-documentation:unit/scim-map-profile-and-units',\n sourceRefs: ['saas-technical-doc:engine-content/scim-map-profile-and-units'],\n markdown: `# Map SCIM profiles and organization units\n\nMap the directory’s actual payload to the profile values the application needs.\nThen, only when department data should control access, map exact department\nvalues to existing organization units.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | The organization administrator and directory engineer who know the real SCIM payload |\n| **Where the mapping applies** | One organization’s SCIM provisioning configuration |\n| **Before you begin** | Capture representative non-production payloads, create every target unit and decide whether department data should be authoritative for unit assignments |\n| **Successful result** | Each required profile field resolves predictably, each approved department maps exactly once, and unmapped or malformed values have a tested outcome |\n\nOpen **Settings → User provisioning → Provisioning** for the organization, then\nedit the attribute and organization-unit mappings. Use the linked SCIM\nconfiguration API reference when the mapping is maintained by automation.\n\n## Map profile values\n\n| Application value | Built-in SCIM path |\n| --- | --- |\n| Email | \\`emails[0].value\\` |\n| Given name | \\`name.givenName\\` |\n| Family name | \\`name.familyName\\` |\n| Display name | \\`displayName\\` |\n\nCustom expressions may use dotted fields, an array index or an \\`eq\\` filter:\n\n- \\`name.givenName\\`\n- \\`emails[primary eq true].value\\`\n- \\`emails[type eq \"work\"].value\\`\n\n> **Test paths against a real directory payload.** A malformed or unmatched\n> expression does not necessarily reject the request. It can produce no value;\n> email may fall back to \\`userName\\`, the primary email or the first email,\n> while another profile field remains empty.\n\n## Understand verified email domains\n\nSCIM mirrors verified domains from the organization’s SSO configuration; it\ndoes not keep another list. A non-empty list restricts admitted email domains.\nAn empty or unavailable list leaves provisioning unrestricted by email domain.\nIf your policy requires a restriction, stop until at least one verified domain\nis visible and a deliberately invalid domain is refused.\n\n## Map a department to a unit\n\nEach mapping binds one exact directory value to one existing unit:\n\n~~~text\n\"Sales\" -> existing Sales organization unit\n~~~\n\nMatching trims surrounding whitespace but is case-sensitive. \\`Sales\\` and\n\\`sales\\` are different. The application does not search by unit name or code,\ndoes not use fuzzy matching and never creates the missing unit.\n\n~~~mermaid\nflowchart LR\n accTitle: Reconcile a directory department to unit access\n accDescr: An exact department value selects one configured unit. With a default unit role, a supported full reconciliation replaces the person's directory-managed unit assignments.\n payload[\"SCIM User department\"] --> exact{\"Exact configured value?\"}\n exact -->|\"Yes\"| unit[\"Existing organization unit\"]\n unit --> role[\"Configured default unit role\"]\n role --> replace[\"Replace desired unit assignments\"]\n exact -->|\"No or blank\"| remove[\"No mapped desired assignment\"]\n~~~\n\nReconciliation becomes active only with at least one explicit mapping and a\ndefault unit role. On supported direct user creation and full replacement, the\ndirectory becomes authoritative: a changed, blank or unmapped department can\nremove former assignments, including manual ones. **PATCH and Bulk do not\ncurrently perform this reconciliation.** Prove the exact operation used by\nyour identity provider.`,\n },\n {\n managedPath: 'user-administration/scim-validate-and-roll-out.md',\n unitRef: 'technical-documentation:unit/scim-validate-and-roll-out',\n sourceRefs: ['saas-technical-doc:engine-content/scim-validate-and-roll-out'],\n markdown: `# Validate and roll out SCIM\n\nDo not enable a full directory population after a successful connection check.\nUse a small controlled group and inspect the resulting user, membership, role,\nunit assignment and sign-in behavior after every change.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | The identity-directory owner, an organization administrator and the owner of the pilot population |\n| **Where validation applies** | One non-production or tightly controlled organization cohort |\n| **Before you begin** | Define expected identities, roles, units and states for every test case, plus the stop and rollback decision |\n| **Successful result** | Real SCIM operations match the expected application state for creation, update, movement, deactivation and recovery before the next cohort is enabled |\n\n> **The current connection-test and provisioning-statistics actions are not\n> readiness evidence.** Prove the integration with real controlled SCIM\n> operations and authoritative application state.\n\n## Run the validation matrix\n\n1. **Create a new person.** Verify the user state, organization membership,\n organization role and enterprise sign-in path.\n2. **Send an existing email.** Confirm that it links to the intended identity\n and does not create a duplicate.\n3. **Change each mapped profile value.** Inspect the destination after the\n directory operation.\n4. **Exercise email verification.** When automatic verification is off, prove\n the pending-verification and resend journey.\n5. **Move a department.** Use a direct full replacement, then confirm the former\n unit assignment was removed.\n6. **Send blank, unmapped and wrong-case departments.** Verify the exact result\n before making mapping authoritative.\n7. **Deactivate a multi-organization person.** Inspect both the global user and\n every affected membership.\n8. **Recover the person.** Confirm that the user and intended membership are\n both **Active** and that enterprise sign-in succeeds.\n\n## Roll out in stages\n\n~~~mermaid\nflowchart LR\n accTitle: Expand SCIM only after each cohort is verified\n accDescr: Begin with controlled identities, then a representative pilot, then broader cohorts. Stop and reconcile differences before proceeding.\n controlled[\"Controlled identities\"] --> pilot[\"Representative pilot\"]\n pilot --> cohort[\"First production cohort\"]\n cohort --> broad[\"Broader population\"]\n controlled -.-> stop[\"Stop on unexplained difference\"]\n pilot -.-> stop\n cohort -.-> stop\n~~~\n\nFor each stage, name the expected count and membership states, reconcile the\nresult, document exceptions and retain a rollback decision. Do not silently\nrepair directory-owned people in the application; fix the authoritative input\nor explicitly move the person to manual ownership.`,\n },\n {\n managedPath: 'user-administration/scim-operate-and-troubleshoot.md',\n unitRef: 'technical-documentation:unit/scim-operate-and-troubleshoot',\n sourceRefs: ['saas-technical-doc:engine-content/scim-operate-and-troubleshoot'],\n markdown: `# Operate and troubleshoot SCIM\n\nOperate SCIM as a security-sensitive directory connection: protect its token,\nreconcile outcomes from authoritative state and investigate errors before\nretrying. A request reaching the service is not proof that provisioning\nsucceeded.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | The directory operator and an organization administrator able to inspect provisioning state |\n| **Where the operation applies** | One organization, directory environment and dedicated SCIM credential |\n| **Before you begin** | Record the affected user, operation, time and redacted response; identify the authoritative owner before making a correction |\n| **Successful result** | The credential or provisioning failure is corrected, one controlled operation succeeds, and the final user, membership, role and unit state is verified |\n\nUse **Settings → User provisioning → Tokens** for token lifecycle work and\n**Provisioning** for configuration and mapping checks. The linked API references\nremain authoritative for exact automation operations and responses.\n\n## Replace or revoke a token\n\nAn in-place rotation is an **immediate cutover**. The previous secret stops\nworking with no overlap. For a planned replacement without interruption:\n\n1. create a second dedicated token;\n2. install it in the identity provider;\n3. prove it with a controlled user operation;\n4. revoke the former token; and\n5. retain only the non-secret metadata needed for review.\n\nRevocation keeps the token record and marks it inactive. A last-used time proves\nthat authenticated traffic reached the service; it does not prove that the user\nchange completed successfully.\n\n## Start from the symptom\n\n| Symptom | First checks |\n| --- | --- |\n| **401** | Token is exact, active, unexpired and sent as a bearer credential |\n| **403** | The organization type permits SCIM and the request belongs to the intended organization |\n| **409** | An existing identity or membership conflicts; inspect it instead of creating a duplicate |\n| **429** | Follow retry information and reduce concurrency |\n| Profile value is missing | Test the exact mapping expression against the real directory payload |\n| Unit did not change | Confirm exact department value and case, explicit mapping, existing unit, default role and a supported direct create/full replacement operation |\n| Person remains unable to sign in | Check enterprise sign-in, global user state and organization membership state separately |\n\n## Recover safely\n\n- Read the SCIM error returned to the identity provider before retrying.\n- Inspect the user, membership, role and unit assignments in the application.\n- Correct the directory or mapping when it owns the person; do not create a\n manual competing state.\n- For deactivation recovery, confirm both the global user and intended\n membership are **Active**.\n- Re-run one controlled operation and inspect its final resource state.\n\nRedact bearer tokens and unnecessary personal data before sharing payloads or\nerrors with support.`,\n },\n {\n managedPath: 'security-and-audit/audit-trail-and-siem.md',\n unitRef: 'technical-documentation:unit/audit-and-siem',\n sourceRefs: ['saas-technical-doc:engine-content/audit-and-siem'],\n markdown: `# Security and audit\n\nThe audit trail answers **who or what acted, what changed, where it happened,\nwhen it happened and whether it succeeded**. Use it to investigate access and\nadministrative activity. Use SIEM export when a security team needs selected\norganization events delivered to its own monitoring system.\n\nThese are two related but separate paths. The application writes the\nauthoritative audit record first. SIEM delivery is a filtered outbound copy. A\nSIEM outage therefore does not erase the application's stored event, and a\nsuccessful SIEM delivery does not replace the source record.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Know the organization and environment, the question being investigated, the authorized reviewer and the smallest useful time range | A stored event or bounded absence is reconciled with current application state, any SIEM delivery issue is treated separately, and controlled evidence has an owner and retention rule |\n\n~~~mermaid\nflowchart LR\n accTitle: Separate authoritative audit creation from SIEM delivery\n accDescr: A protected action creates an immutable application audit record. The organization filter may select that event for formatting and delivery to the SIEM. Failed delivery moves to the dead-letter queue while the original record remains available for investigation.\n action[\"Protected action or access decision\"] --> record[\"Immutable application audit record\"]\n record --> investigate[\"In-product investigation and bounded JSON export\"]\n record --> filter{\"Organization SIEM filter selects event?\"}\n filter -->|No| retained[\"Record remains in audit trail\"]\n filter -->|Yes| deliver[\"Format and deliver to SIEM\"]\n deliver -->|Success| siem[\"Organization SIEM\"]\n deliver -->|Failure| dlq[\"SIEM delivery queue for recovery\"]\n~~~\n\n## Understand what the trail proves\n\nAn audit row records that the application observed a particular action or\ndecision at a time. Its event identifier follows that event across retained and\nexported copies; its correlation identifier links activity from the same\nrequest or job. Actor, source, organization, outcome and event-specific data\nexplain the recorded context.\n\nThe trail does **not** automatically prove that:\n\n- the resource still has the same state now;\n- a declared event name is actually emitted by every operation;\n- the SIEM received its copy;\n- a broad export contains every matching row; or\n- a successful administrative action was low risk.\n\nReconcile material findings with the current authoritative resource. Treat a\nmissing expected row as a question about scope, filters, time and producer\ncoverage—not immediate proof that no action happened.\n\n## Keep actor and authority visible\n\n| Actor description | Meaning for investigation |\n| --- | --- |\n| Named person | The action is attributed to that person; verify the membership and role that applied at the time |\n| Machine | An API key or OAuth client acted; identify the credential record and owning workload |\n| System | A scheduled, internal or lifecycle process acted by design |\n| Unattributed | A principal was expected but could not be resolved; treat this as an anomaly to investigate |\n\nThe actor can differ from the person or resource affected by the action. Keep\nboth in the investigation so an administrator changing another person's access\nis not misread as self-service.\n\n## Choose the task you need\n\n- [Investigate an audit event](/security-and-audit/investigate-event) from a\n bounded symptom, time and organization scope.\n- [Review access and privileged changes](/security-and-audit/review-access-changes)\n without relying on declared-but-unemitted event names.\n- [Export a bounded audit window](/security-and-audit/export-audit-records) as\n JSON for an approved investigation.\n- [Configure organization SIEM export](/security-and-audit/configure-siem) with\n the appropriate format, authentication and event filter.\n- [Operate and troubleshoot SIEM delivery](/security-and-audit/operate-siem)\n from retries and dead-letter state.\n- [Protect and retain audit evidence](/security-and-audit/protect-evidence)\n without turning a diagnostic copy into an uncontrolled data store.\n\nClose each task with the question, organization/environment, filters and time\nboundary, event and correlation identifiers, current-state comparison, reviewer\ndecision and owned follow-up. Never place credentials, complete tokens or an\nunrestricted evidence export in an ordinary support ticket.`,\n },\n {\n managedPath: 'security-and-audit/investigate-event.md',\n unitRef: 'technical-documentation:unit/investigate-audit-event',\n sourceRefs: [\n 'saas-technical-doc:engine-content/investigate-audit-event',\n 'source:consumer-fact:organization-audit-trail',\n ],\n 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.`,\n },\n {\n managedPath: 'security-and-audit/review-access-changes.md',\n unitRef: 'technical-documentation:unit/review-privileged-and-access-changes',\n sourceRefs: ['saas-technical-doc:engine-content/review-privileged-and-access-changes'],\n markdown: `# Review access and privileged changes\n\nAn access review should connect the authority that existed, the action that was\nattempted and the authority that exists now. Searching only for a person's name\ncan miss machine access, system-initiated lifecycle work and changes made to the\nperson by another administrator.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Define the organization, review period, people and machine identities in scope, the reviewer and the approved source of current access | Every material grant, refusal and removal is reconciled with current membership and role state, exceptions have owners, and the review decision retains traceable evidence |\n\n## Ask a reviewable question\n\n“Review all access” is too broad to prove. Start with one question whose answer\nchanges an access decision, for example:\n\n- Who gained or lost an organization-wide role during this period?\n- Which people were invited, suspended, reactivated or removed?\n- Which organization-unit assignments changed for a sensitive resource?\n- Which API key or OAuth client roles changed, and who approved the change?\n- Which refused privileged operations indicate repeated misuse or a broken\n administrative process?\n\nRecord the organization, start and end time, target identities and event\nfamilies before searching. Use a bounded export only after the search is narrow\nenough to explain; a large download does not make the review more complete.\n\n## Review the important event families\n\n- **Authentication:** successful and failed sign-in, lockout, SSO enforcement,\n credential and multifactor changes.\n- **Authorization:** refused operations, application-role changes,\n organization-role changes and organization-unit grants or revocations.\n- **User lifecycle:** invitation or membership operations, suspension,\n reactivation and removal evidence.\n- **Organization security configuration:** SSO, SCIM, SIEM and authentication\n policy changes.\n- **Machine activity:** machine authentication and the protected operation a\n machine credential exercised through an external surface.\n\nAdministrative success is not automatically low importance. Role changes and\nother privilege-bearing operations are classified to remain visible even when\nthey were authorized.\n\nDeclared event names are not evidence on their own. Review stored records that\nwere actually emitted, and use generic protected-operation evidence when a\ndedicated lifecycle name is not produced. Absence of one expected label does\nnot prove the underlying change was unaudited.\n\n~~~mermaid\nflowchart TD\n accTitle: Review a privilege change from decision to current state\n accDescr: The reviewer identifies the target identity and scope, finds the role or access operation, verifies actor and outcome, follows correlated events, and compares the recorded change with current membership and role state.\n target[\"Identity and organization under review\"] --> event[\"Find grant, revoke, refusal or lifecycle event\"]\n event --> actor[\"Verify actor, source and outcome\"]\n actor --> correlation[\"Follow related correlation events\"]\n correlation --> current[\"Compare with current membership and role state\"]\n current --> decision{\"Access still appropriate?\"}\n decision -->|Yes| evidence[\"Record review decision\"]\n decision -->|No| remediate[\"Use the normal access-change workflow\"]\n~~~\n\nUse the user-administration procedures to remediate access. Never edit audit\nrows to make current state appear consistent: audit records have no update or\ndelete operation.\n\n## Close the review against current state\n\n| Finding | Verify now | Close with |\n| --- | --- | --- |\n| Intended grant | Membership is active and the current role still matches the approved work | Reviewer, approval reference and next review date |\n| Excess or unexplained access | Current membership, organization-unit assignment, API key or OAuth client still carries it | Normal access-removal workflow plus the resulting audit evidence |\n| Refused privileged action | Actor, operation, reason and correlated attempts | Explained benign cause or an owned security investigation |\n| Access removed in the audit trail | Current state no longer authorizes the identity and no sibling credential preserves the same access | Verification time and the identity or credential checked |\n| Trail and current state disagree | Scope, time boundary, propagation and whether a later event superseded the first | Reconciliation decision; never a rewritten audit row |\n\nFinish by recording what was reviewed, the filters used, the current-state\nchecks performed, unresolved exceptions and who owns each follow-up. Exclude\ncredentials and unrestricted personal data from the review record.`,\n },\n {\n managedPath: 'security-and-audit/export-audit-records.md',\n unitRef: 'technical-documentation:unit/export-audit-records',\n sourceRefs: ['saas-technical-doc:engine-content/export-audit-records'],\n markdown: `# Export a bounded audit window\n\nUse the audit export operation when an organization administrator needs a small,\nreviewable set of source records for an investigation. This is a synchronous\nJSON response, not an archive job, CSV download or continuing SIEM feed.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Have an approved investigation purpose, the intended organization, a narrow time window and a protected destination | The response is small enough to review, its scope is verified and the retained copy has an owner and deletion rule |\n\n## Choose the right evidence path\n\n| Need | Use | Why |\n| --- | --- | --- |\n| Inspect events interactively | Audit search or list | You can refine filters before creating another copy |\n| Collect up to 100 matching source records | Bounded audit export | It returns one synchronous JSON evidence window with a matching count |\n| Deliver selected future events continuously | SIEM export | The receiver gets filtered events as they occur, with delivery and recovery state |\n| Preserve evidence under a long-term retention programme | Governed archival process | Retention, access, integrity and deletion require controls beyond a one-off download |\n\nDo not use a broader mechanism merely because it is available. A one-off\ninvestigation normally starts with search, then exports only the records needed\nfor review.\n\n## Define the window before exporting\n\nFilter by the narrowest useful combination of event type, category, severity,\nuser, organization, application and creation-time range. An authenticated\norganization scope takes precedence over a caller-supplied organization filter.\nThe response contains at most **100 records** and reports the total matching\ncount so you can tell when the requested investigation exceeds one bounded\nwindow.\n\nAsk these questions before sending the request:\n\n- Which event, person, credential, resource or correlation starts the review?\n- Which organization and environment own the evidence?\n- What is the smallest time range that includes the suspected action and its\n immediate consequences?\n- Which filters can exclude unrelated people or business activity?\n- Who is authorized to receive the exported copy, and when should it be\n deleted?\n\n~~~mermaid\nflowchart TD\n accTitle: Export a small, controlled audit evidence window\n accDescr: The investigator defines a purpose and authorized organization, narrows filters and time, requests up to one hundred JSON records, compares the returned count with the matching total, and either protects the result or narrows the request again.\n question[\"State the investigation question\"] --> scope[\"Confirm organization and environment\"]\n scope --> filter[\"Choose narrow event, actor and time filters\"]\n filter --> request[\"Request up to 100 JSON records\"]\n request --> count{\"totalCount fits this window?\"}\n count -->|Yes| verify[\"Verify records and preserve identifiers\"]\n count -->|No| narrow[\"Narrow the filter or time window\"]\n narrow --> request\n verify --> protect[\"Store, approve and delete under policy\"]\n~~~\n\nThe count is part of the evidence. If **totalCount** is greater than the returned\nrecords, the response is incomplete for that filter. Narrow the investigation;\ndo not describe the first 100 records as the complete result.\n\n## Export and verify the response\n\n1. Confirm the caller is authorized to export audit evidence for the intended\n scope. The exact API-reference operation defines the admitted roles.\n2. Submit the narrow filters and a **maxRecords** value from 1 through 100.\n3. Confirm the response format is **json** and retain **totalCount** with the\n records.\n4. Verify the organization, application and creation-time range on the returned\n events before using them as evidence.\n5. Preserve event IDs and correlation IDs byte-for-byte so another reviewer can\n trace the same activity.\n6. Compare material changes or outcomes with the application's current\n authoritative state. An audit row proves what was recorded; it does not prove\n that the current resource still has that state.\n\n## Handle the result safely\n\nTreat the exported JSON as a new controlled copy of security and potentially\npersonal information:\n\n- record who approved it, who created it, the purpose, filters, time and\n **totalCount**;\n- store it only in an approved location with named access and a deletion date;\n- protect integrity when it is used as formal evidence;\n- redact unnecessary personal data before attaching a subset to a ticket;\n- never place the export in source control, ordinary chat or an unrestricted\n shared folder.\n\nThe export does not remove records from the application. If you need continuous\ndelivery, configure SIEM export. If you need long-term archival, use the\napplication's governed archival policy rather than repeatedly downloading\noverlapping JSON windows.\n\n## If the export is empty or incomplete\n\n| Result | Check next |\n| --- | --- |\n| No records | Organization/environment, time zone, time range and whether the event was actually emitted |\n| Fewer records than expected | Event category/type and actor filters, then compare **totalCount** |\n| Exactly 100 records with a larger **totalCount** | Narrow the time range or other filters; the response is a bounded window, not pagination |\n| A forbidden response | Caller authority and the exact operation contract; do not switch to a broader credential without approval |\n| A timeout or lost response | Read or repeat a narrow, idempotent export only after confirming no uncontrolled copy was stored by the caller |`,\n },\n {\n managedPath: 'security-and-audit/configure-siem.md',\n unitRef: 'technical-documentation:unit/configure-siem-export',\n sourceRefs: [\n 'saas-technical-doc:engine-content/configure-siem-export',\n 'source:consumer-fact:organization-siem-export',\n ],\n markdown: `# Configure organization SIEM export\n\nSIEM export sends selected organization audit events to one webhook destination.\nCreate a destination dedicated to the organization and environment, then choose\nthe authentication, wire format and filters your receiver can actually verify.\n\n| Before you begin | Successful result |\n| --- | --- |\n| The organization security owner and SIEM owner agree on destination, TLS, authentication, event scope, format, volume, retention and a controlled test event | One organization/environment sends only the approved event set, the receiver validates and correlates it, failures are recoverable, and the destination secret remains protected |\n\n~~~mermaid\nflowchart TD\n accTitle: Configure a bounded organization SIEM export\n accDescr: The organization and SIEM owners prepare one receiver, choose authentication and a format, select a narrow category and severity filter, keep export disabled while validating configuration, enable it for one controlled event, compare the received copy with the source audit row, then expand deliberately.\n owners[\"Agree owners, organization and receiver\"] --> receiver[\"Prepare TLS, authentication and acknowledgement\"]\n receiver --> format[\"Choose one receiver-supported format\"]\n format --> filter[\"Select minimum event set and severity\"]\n filter --> disabled[\"Save while export remains disabled\"]\n disabled --> enable[\"Enable and perform one controlled event\"]\n enable --> compare[\"Compare event ID, scope, time, actor and outcome\"]\n compare --> expand[\"Expand only after volume and recovery checks\"]\n~~~\n\nSIEM export is an organization-routed copy of source audit events. Configure one\nreceiver per intended organization/environment boundary; do not use a shared\ndestination when its access and retention rules cannot preserve that separation.\n\n## Follow one event from source record to searchable copy\n\n~~~mermaid\nsequenceDiagram\n accTitle: From application audit record to searchable SIEM copy\n accDescr: The application records an audit event, applies the organization export filter, formats one outbound event, authenticates an HTTPS request, and sends it to the receiver. A successful HTTP response acknowledges the configured delivery boundary; the SIEM then parses and indexes the copy. Operators prove completion by searching for the source event identifier. Failed delivery follows retry and dead-letter recovery without removing the source audit record.\n participant Source as Source audit trail\n participant Export as Organization exporter\n participant Receiver as Receiver or relay\n participant SIEM as SIEM index\n actor Operator as Security operator\n Source->>Export: Eligible audit event\n Export->>Export: Apply filter and format one event\n Export->>Receiver: Authenticated HTTPS request\n alt Receiver acknowledges configured boundary\n Receiver-->>Export: Successful HTTP response\n Receiver->>SIEM: Parse, transform and index\n Operator->>SIEM: Search exact eventId\n SIEM-->>Operator: Searchable correlated copy\n else Receiver refuses or times out\n Receiver-->>Export: Error or timeout\n Export->>Export: Retry, then capture recoverable failure\n end\n~~~\n\nThere are three different facts to verify: **the source event exists**, **the\nreceiver acknowledged the request**, and **the transformed event is searchable\nin the intended index or table**. An HTTP 2xx response proves only the delivery\nboundary implemented by that receiver. It is not automatically proof that a\nparser, transformation, index or detection rule accepted the event.\n\n## Decide whether direct delivery is compatible\n\n| Receiver requirement | Recommended path | Why |\n| --- | --- | --- |\n| One HTTPS request containing one JSON object, with a static header or HMAC credential | Test direct delivery | This matches the current structured-JSON worker closely |\n| A provider-specific wrapper around the event | Use a narrow relay unless the exact endpoint accepts the native envelope | The relay owns the wrapper while preserving source identifiers |\n| Short-lived OAuth access tokens or managed identity | Use a provider-side relay | Token acquisition and refresh do not belong in a static credential field |\n| A JSON array or provider batch protocol | Use a relay that batches deliberately | Current delivery is one event per request; configured batch fields are reserved |\n| A syslog, agent, queue or private-network input | Use an adapter or relay inside that boundary | The application sends outbound HTTPS webhooks, not those transports |\n| CEF, LEEF or OCSF ingestion | Test actual emitted samples with the receiver | A format name does not prove field mapping, escaping, severity or class compatibility |\n\nPrefer the smallest component that makes the contracts compatible. A relay is\nnot a generic event platform: it should authenticate before parsing, preserve\nthe source event and correlation identifiers, perform one documented\ntransformation, expose bounded health signals and fail without silently\ndiscarding the event.\n\n## Choose the delivery contract\n\nThe following table is generated from the maintained SIEM configuration schema\nand resource specification. It distinguishes enforced values from reserved\nconfiguration so an accepted field is not mistaken for working delivery\nbehavior.\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#configurationMarkdown}}\n\n### Authentication values\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#authenticationValuesMarkdown}}\n\n### Wire-format values\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#formatValuesMarkdown}}\n\nChoose the simplest format the receiver can validate end to end:\n\n| Format | Use when | Verify before rollout |\n| --- | --- | --- |\n| Structured JSON | The receiver can preserve named fields and nested event data | Schema/field parsing, timestamps, identifiers and unknown-field handling |\n| CEF | The receiver has a tested CEF ingestion path | Header and extension parsing, escaping and the receiver's event classification |\n| LEEF | The receiver has a tested LEEF/QRadar path | Tab-delimited attributes, escaping and event mapping |\n| OCSF | The receiver consumes the emitted OCSF class documents | Class, activity, required fields and receiver validation for the actual event samples |\n\nDo not choose a format from its name alone. Preserve a receiver-tested sample\nfor each event family that matters to detection; syntactically accepted input\ncan still be mapped to the wrong fields or severity by the downstream product.\n\nAuthentication credentials are write-only secrets. A read returns a masked\nstored-credential marker, not the secret. Leaving that marker unchanged during\nan edit preserves the stored value; entering a new value replaces it. Never\ncopy the secret into a ticket or detection rule.\n\n## Configure filters from their exact values\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#filterValuesMarkdown}}\n\nThe optional \\`specificEventTypes\\` list is an **exact identifier allowlist**.\nIt is not a substring, prefix, regular expression or wildcard filter. Add an\nidentifier only after confirming that the corresponding event is emitted in the\napplication path you operate.\n\n## Configure delivery behavior\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#deliveryValuesMarkdown}}\n\nThe current worker posts **one event per HTTP request**. Do not configure a\nreceiver, load balancer or billing estimate on the assumption that \\`batchSize\\`\nor \\`batchWindowSeconds\\` reduces request volume. The\n\\`includeRawEventData\\` and \\`includeDeviceContext\\` flags are also reserved in\nthe current runtime: changing them does not remove those fields from the emitted\nenvelope. Treat data minimization at the receiver as necessary until those\nconfiguration controls are implemented end to end.\n\n## Filter for purpose and volume\n\nStart with the categories needed by the monitoring use case and a minimum\nseverity that preserves administrative and security-relevant activity. Add an\nevent-type allowlist only when the receiver intentionally needs that narrower\nset. An allowlist can silently exclude newly introduced event types, so record\nits owner and review it when the application's event catalogue changes.\n\nFilters govern future delivery copies; they do not delete the source audit\ntrail. A narrow SIEM feed is therefore not evidence that no other audit activity\nexists in the application.\n\n## Roll out deliberately\n\n1. Keep export disabled while the receiver, TLS and authentication are prepared.\n2. Start with structured JSON and a narrow event filter that includes one\n controlled administrative event.\n3. Enable export and perform the controlled action in the intended organization.\n4. Match the received event ID, timestamp, organization, outcome and correlation ID.\n5. Trigger a controlled event outside the filter and confirm it remains in the\n source trail but is not delivered to this receiver.\n6. Exercise an acknowledged receiver response and one safe temporary failure so\n ownership of retry/dead-letter recovery is known.\n7. Expand categories and lower the severity threshold only after the receiver\n handles expected volume and redaction.\n\nConfiguration is cached by the running application for up to five minutes.\nEnabling may therefore miss exports during that interval, and changing a\ndestination may continue sending to the former receiver until the cache expires.\nTreat a destination change as a security operation and verify the old receiver\nhas stopped receiving before closing the change.\n\nFor credential rotation or destination replacement, keep the change window and\nold/new receiver ownership explicit. Verify the current receiver accepts a new\ncontrolled event and the former receiver no longer receives selected traffic\nafter the cache window. Retain configuration approval, non-secret destination\nidentity, format/filter choices, test event and correlation IDs, delivery result\nand recovery owner—never the bearer token, API-key value or HMAC secret.\n\n## Format standards and receiver references\n\n- OpenText’s [Common Event Format implementation standard](https://www.microfocus.com/documentation/arcsight/arcsight-smartconnectors-24.4/cef-implementation-standard/)\n describes CEF header and extension construction. Validate the application’s\n actual event samples against the target connector rather than assuming every\n CEF consumer maps extensions identically.\n- IBM documents [LEEF event components](https://www.ibm.com/docs/en/qradar-on-cloud?topic=overview-leef-event-components)\n and [predefined LEEF attributes](https://www.ibm.com/docs/en/qradar-on-cloud?topic=overview-predefined-leef-event-attributes)\n for QRadar ingestion and field mapping.\n- The [OCSF schema browser](https://schema.ocsf.io) and\n [OCSF schema repository](https://github.com/ocsf/ocsf-schema) define the open\n event classes and attributes. Confirm the emitted class, activity and\n required fields for every selected event family.\n\nThese external standards describe receiver-side expectations. The generated\nconfiguration tables above remain the authority for values and behavior this\napplication actually supports.`,\n },\n {\n managedPath: 'security-and-audit/siem-splunk.md',\n unitRef: 'technical-documentation:unit/siem-splunk',\n sourceRefs: [\n 'saas-technical-doc:engine-content/siem-splunk',\n 'source:consumer-fact:organization-siem-export',\n ],\n markdown: `# Send audit events to Splunk\n\nSplunk HTTP Event Collector (HEC) accepts events over HTTPS with a token in the\n\\`Authorization\\` header. The application can supply that header, but its native\nstructured JSON body is a security-audit envelope—not Splunk’s HEC\n\\`{\"event\": ...}\\` wrapper. **Use a small controlled relay unless your chosen HEC\nendpoint and source type have been proven to accept and extract the exact body.**\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#markdown}}\n\n~~~mermaid\nflowchart LR\n audit[\"Organization audit event\"] --> exporter[\"Application SIEM export\"]\n exporter -->|\"JSON + authenticated HTTPS\"| relay[\"Owned HEC relay\"]\n relay -->|\"HEC event wrapper\"| hec[\"Splunk HEC\"]\n hec --> index[\"Dedicated index and source type\"]\n index --> search[\"Search by eventId and correlationId\"]\n~~~\n\n## Prepare Splunk\n\n1. Create a dedicated Splunk index or confirm the approved existing index.\n2. In Splunk Cloud or Splunk Enterprise, create an HEC token dedicated to this\n application organization and environment.\n3. Assign the token only to the intended index and choose a JSON-capable source\n type. Wait until token deployment is complete before testing.\n4. Record the HEC base URL, token owner, index, source type, rotation process and\n retention policy. Store the token only in approved secret stores.\n\nSplunk’s event endpoint expects a body shaped like:\n\n~~~json\n{\n \"time\": 1776631800,\n \"host\": \"application-production\",\n \"source\": \"application-security-audit\",\n \"sourcetype\": \"_json\",\n \"index\": \"security\",\n \"event\": {\n \"eventId\": \"7b45a61c-9bcc-4bf2-9a29-0f111bff6d07\",\n \"eventType\": \"user_login_failed\",\n \"organizationId\": \"org_example\",\n \"severity\": \"warning\"\n }\n}\n~~~\n\nThe relay owns this wrapper and any approved metadata; it must preserve the\napplication event object without renaming \\`eventId\\`, \\`correlationId\\`, actor,\norganization, timestamp, outcome or severity fields.\n\n### Choose the acknowledgement boundary\n\nA normal HEC success response confirms that HEC accepted the request. Splunk\nalso supports **indexer acknowledgement**, where a client submits a channel\nidentifier and later checks whether the event reached the indexing pipeline.\nIf the relay uses that mode, return success to the application only after the\nrelay’s documented durability boundary; do not hold the application request\nopen indefinitely while waiting for a search result.\n\nWhichever mode you choose, the operating proof is still an exact\n\\`eventId\\` search in the intended index. Record separately whether a failure\nhappened before HEC acceptance, while awaiting an indexer acknowledgement, or\nafter indexing during parsing and field extraction.\n\n## Configure the application-to-relay request\n\nRecommended application settings:\n\n| Setting | Value |\n| --- | --- |\n| Destination | Relay HTTPS URL dedicated to the organization/environment |\n| Authentication | \\`hmac_sha256\\` or a dedicated \\`api_key_header\\` |\n| Format | \\`json_structured\\` |\n| Delivery | One event per request; choose timeout/retry values below the relay’s bounded acknowledgement time |\n\nIf a controlled test proves direct HEC compatibility, configure:\n\n| Setting | Direct HEC value |\n| --- | --- |\n| \\`authMethod\\` | \\`api_key_header\\` |\n| \\`authHeaderName\\` | \\`Authorization\\` |\n| \\`authCredential\\` | The complete value \\`Splunk HEC_TOKEN\\`, including the \\`Splunk \\` prefix |\n| \\`webhookUrl\\` | The exact HEC event or raw endpoint validated by the Splunk owner |\n\nThe API-key-header mode sends the configured credential verbatim. Do not choose\n\\`bearer_token\\`: it would send \\`Authorization: Bearer ...\\`, which is not\nSplunk HEC token authentication.\n\n## Prove ingestion, not only HTTP acceptance\n\n1. Keep broad export disabled and select one controlled event type.\n2. Trigger the event and find the source audit row.\n3. Confirm relay/HEC HTTP acceptance without logging the token.\n4. Search the intended Splunk index for the exact \\`eventId\\`.\n5. Verify organization, timestamp, event type, severity, actor/outcome and\n correlation identifier.\n6. Trigger an event outside the filter and confirm it remains only in the source\n audit trail.\n7. Temporarily refuse one request, restore the receiver and prove dead-letter\n recovery without creating a duplicate indexed event.\n\n## Splunk documentation to keep with the runbook\n\n- Splunk’s [HTTP Event Collector examples](https://help.splunk.com/en/splunk-enterprise/get-data-in/collect-http-event-data/http-event-collector-examples)\n show the HEC authorization header, event wrapper and endpoint shapes used to\n validate the relay output.\n- Splunk’s [HEC indexer acknowledgement](https://help.splunk.com/en/splunk-enterprise/get-started/get-data-in/9.2/get-data-with-http-event-collector/about-http-event-collector-indexer-acknowledgment)\n documentation explains the optional channel and acknowledgement protocol.\n\nKeep the tested HEC endpoint, source type, acknowledgement mode and sample\nsearch beside these links. Provider documentation defines Splunk’s contract;\nthis guide defines the application envelope that must be conserved.`,\n },\n {\n managedPath: 'security-and-audit/siem-microsoft-sentinel.md',\n unitRef: 'technical-documentation:unit/siem-microsoft-sentinel',\n sourceRefs: [\n 'saas-technical-doc:engine-content/siem-microsoft-sentinel',\n 'source:consumer-fact:organization-siem-export',\n ],\n markdown: `# Send audit events to Microsoft Sentinel\n\nMicrosoft Sentinel commonly receives custom data through the Azure Monitor Logs\nIngestion API. That API requires a Data Collection Rule (DCR), a matching JSON\nschema and Microsoft Entra OAuth authorization. The application’s SIEM exporter\nuses a static outbound credential and posts one JSON object per event; it does\nnot acquire or refresh Azure OAuth tokens and does not wrap events as the JSON\narray expected by Logs Ingestion. **Use an Azure-hosted relay rather than pointing\nthe application directly at the Logs Ingestion API.**\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#markdown}}\n\n~~~mermaid\nflowchart LR\n app[\"Application SIEM export\"] -->|\"HMAC or API-key authenticated JSON\"| relay[\"Azure Function, Logic App or API Management relay\"]\n relay --> transform[\"Validate, transform and batch as an array\"]\n transform -->|\"Entra OAuth token\"| dcr[\"Azure Monitor DCR ingestion endpoint\"]\n dcr --> table[\"Log Analytics custom table\"]\n table --> sentinel[\"Microsoft Sentinel analytics\"]\n~~~\n\n## Prepare Azure Monitor and Sentinel\n\n1. Create a custom Log Analytics table whose columns preserve the application\n event identifiers, timestamp, organization, actor, outcome, severity and\n event-specific data needed by detections.\n2. Create a DCR with a direct Logs Ingestion endpoint (or a Data Collection\n Endpoint when private-link architecture requires it), the input stream and a\n transformation into the table.\n3. Create a relay identity and grant it only the DCR ingestion permission it\n needs. Keep Azure client credentials or managed identity inside Azure.\n4. Deploy an HTTPS relay that validates the application request **before**\n parsing, converts the event into the DCR input schema, sends a JSON array to\n Logs Ingestion and returns success only after the chosen delivery boundary.\n\n### Relay input contract\n\nUse \\`json_structured\\` so the relay receives the complete application envelope.\nFor HMAC authentication, validate:\n\n~~~text\nX-Signature-256: sha256=LOWERCASE_HEXADECIMAL_HMAC\n~~~\n\nCompute HMAC-SHA256 over the exact received bytes with the shared secret and use\na constant-time comparison. Do not parse and reserialize before verification.\nAlternatively, configure a dedicated API-key header accepted only by the relay.\n\nThe relay should emit a DCR record similar to:\n\n~~~json\n[\n {\n \"TimeGenerated\": \"2026-08-20T19:30:00.000Z\",\n \"EventId\": \"7b45a61c-9bcc-4bf2-9a29-0f111bff6d07\",\n \"CorrelationId\": \"req_01HXEXAMPLE\",\n \"OrganizationId\": \"org_example\",\n \"EventType\": \"user_login_failed\",\n \"Severity\": \"warning\",\n \"Outcome\": \"failure\"\n }\n]\n~~~\n\n## Configure and prove the path\n\n1. Configure the application destination as the relay URL, authentication as\n HMAC or API-key header, and format as structured JSON.\n2. Start with one exact event type and leave broad categories disabled.\n3. Trigger the controlled event and record its source \\`eventId\\`.\n4. Prove signature/API-key validation at the relay, DCR acceptance, arrival in\n the custom table and Sentinel queryability by the same \\`eventId\\`.\n5. Compare timestamp, organization, actor, outcome and severity with the source\n row; a transformed row must remain traceable.\n6. Refuse an invalid signature and malformed schema without forwarding either.\n7. Simulate an Azure ingestion failure, restore the path, re-enqueue one\n dead-letter row and verify the table contains one intended event.\n\nDo not store a short-lived Azure access token as the application’s static bearer\ncredential; token acquisition and renewal belong to the relay identity.\n\n## Microsoft documentation to keep with the runbook\n\n- The [Logs Ingestion API overview](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/logs-ingestion-api-overview)\n defines the endpoint, JSON-array and OAuth boundaries the relay must satisfy.\n- The [Data Collection Rule overview](https://learn.microsoft.com/en-us/azure/azure-monitor/data-collection/data-collection-rule-overview)\n explains the input stream, destination and transformation relationship.\n- [Data collection transformations](https://learn.microsoft.com/en-us/azure/azure-monitor/data-collection/data-collection-transformations)\n describes the KQL transformation applied before the target table.\n- Microsoft Sentinel’s [data connector reference](https://learn.microsoft.com/en-us/azure/sentinel/connect-data-sources)\n helps the security owner decide whether the resulting table should feed a\n custom connector, analytics rule or another supported ingestion route.\n\nPin the DCR immutable identifier, stream name, table, transformation revision\nand relay identity in the runbook. A portal display name alone is not enough to\nreconstruct or audit the delivery path.`,\n },\n {\n managedPath: 'security-and-audit/siem-elastic.md',\n unitRef: 'technical-documentation:unit/siem-elastic',\n sourceRefs: [\n 'saas-technical-doc:engine-content/siem-elastic',\n 'source:consumer-fact:organization-siem-export',\n ],\n markdown: `# Send audit events to Elastic\n\nElastic Filebeat’s \\`http_endpoint\\` input can receive an HTTPS POST containing a\nJSON object and can validate a fixed secret header or an HMAC signature. This is\na close match for the application’s one-event structured JSON delivery. Run the\nlistener behind a production TLS and network boundary; the example below is a\nstarting contract, not a complete Elastic deployment.\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#markdown}}\n\n## Configure the receiver\n\nThe following Filebeat shape places the application envelope at the document\nroot and validates a dedicated header:\n\n~~~yaml\nfilebeat.inputs:\n - type: http_endpoint\n enabled: true\n listen_address: 0.0.0.0\n listen_port: 8443\n url: /application-security-audit\n prefix: \".\"\n content_type: application/json\n secret.header: X-Application-SIEM-Token\n secret.value: \\${APPLICATION_SIEM_TOKEN}\n ssl.enabled: true\n ssl.certificate: /run/secrets/tls.crt\n ssl.key: /run/secrets/tls.key\n tags: [application-security-audit]\n~~~\n\nConfigure the application with:\n\n| Setting | Value |\n| --- | --- |\n| \\`webhookUrl\\` | Public/proxied HTTPS endpoint ending in \\`/application-security-audit\\` |\n| \\`authMethod\\` | \\`api_key_header\\` |\n| \\`authHeaderName\\` | \\`X-Application-SIEM-Token\\` |\n| \\`authCredential\\` | The same dedicated secret value, stored once |\n| \\`eventFormat\\` | \\`json_structured\\` |\n\nFor HMAC instead, configure the Elastic input’s HMAC header as\n\\`X-Signature-256\\`, type \\`sha256\\`, prefix \\`sha256=\\` and the same shared key;\nthen select \\`hmac_sha256\\` in the application. Keep either mechanism scoped to\none organization/environment.\n\n## Map and retain the event\n\nKeep the complete application envelope in a controlled namespace, then add\nElastic Common Schema (ECS) fields through an ingest pipeline. Do not destroy\nthe source value merely to make it resemble an ECS value.\n\n~~~mermaid\nflowchart LR\n accTitle: Preserve the source event while creating an Elastic search view\n accDescr: Filebeat receives the application JSON envelope. An ingest pipeline preserves it under an application audit namespace, copies only semantically compatible values into Elastic Common Schema fields, sends the document to a scoped data stream, and makes source and normalized identifiers available to searches and detections.\n receive[\"Filebeat HTTP endpoint\"] --> pipeline[\"Ingest pipeline\"]\n pipeline --> original[\"Preserved application.audit fields\"]\n pipeline --> ecs[\"Explicit ECS mappings\"]\n original --> stream[\"Scoped data stream\"]\n ecs --> stream\n stream --> search[\"Search, dashboards and detections\"]\n~~~\n\n| Application field | Safe Elastic treatment | Important condition |\n| --- | --- | --- |\n| \\`timestamp\\` | Copy to \\`@timestamp\\` | Parse as the source-event time; keep receiver ingestion time distinct |\n| \\`eventId\\` | Copy to \\`event.id\\` | Preserve as an exact keyword for correlation and deduplication |\n| \\`eventType\\` | Copy to \\`event.action\\` | Keep the original identifier unchanged |\n| \\`eventCategory\\` | Preserve under \\`application.audit.category\\` | Map to ECS \\`event.category\\` only when the value is translated to an allowed ECS category |\n| \\`severity\\` | Preserve the source label; optionally derive numeric \\`event.severity\\` | ECS severity is numeric, so a text value such as \\`warning\\` needs an explicit mapping |\n| \\`outcome\\` | Preserve the source value; copy to \\`event.outcome\\` only after validation | ECS restricts outcome values; do not copy an incompatible value blindly |\n| \\`correlationId\\` | Preserve under \\`application.audit.correlation_id\\` | Use \\`trace.id\\` only when the identifier truly represents the same distributed trace |\n| \\`organizationId\\` and \\`applicationId\\` | Preserve as exact scoped keywords | Use them in data-stream access controls and investigation filters |\n\nActor/user identifiers and authentication source remain important for\ninvestigation, but map them only after deciding whether each identifier denotes\nthe acting account, the affected account or another subject. A convenient\n\\`user.id\\` mapping that merges those roles makes investigations misleading.\n\nApply an ingest pipeline or index template deliberately. Do not let dynamic\nmapping turn identifiers into analyzed text or allow arbitrary event data to\ncause uncontrolled field growth.\n\n## Prove end-to-end behavior\n\n1. Run the receiver on a controlled endpoint and confirm TLS trust from the\n application runtime.\n2. Send one selected test event and find it in the source audit trail.\n3. Confirm the Elastic input acknowledges the request, then search by exact\n \\`eventId\\` in the target data stream/index.\n4. Compare organization, time, event type, severity, actor and outcome.\n5. Send a wrong header value or signature and confirm Elastic returns 401 and\n the document is absent.\n6. Return a temporary 503, restore the endpoint and prove dead-letter recovery\n without an unintended duplicate detection.\n7. Record receiver capacity for **one request per selected event**; application\n batching fields are currently reserved and do not reduce that rate.\n\n## Elastic documentation to keep with the runbook\n\n- The [Filebeat HTTP Endpoint input reference](https://www.elastic.co/docs/reference/beats/filebeat/filebeat-input-http_endpoint)\n defines JSON-object handling, secret headers, HMAC validation, response codes\n and acknowledgement options.\n- The [ECS event field reference](https://www.elastic.co/docs/reference/ecs/ecs-event)\n defines fields such as \\`event.id\\`, \\`event.action\\`, \\`event.category\\`,\n \\`event.outcome\\` and \\`event.severity\\`.\n- Elastic’s [custom fields guidance](https://www.elastic.co/docs/reference/ecs/ecs-custom-fields-in-ecs)\n and [ECS mapping guidelines](https://www.elastic.co/docs/reference/ecs/ecs-guidelines)\n explain how to preserve application-owned semantics without creating field\n conflicts.\n- The Elastic Security [SIEM field reference](https://www.elastic.co/docs/reference/security/fields-and-object-schemas/siem-field-reference)\n identifies fields used by detections and investigations; treat it as a\n consumer requirement, not permission to invent missing source meaning.\n\nVersion the index template and ingest pipeline with the runbook. Re-run the\ncontrolled-event proof after changing either one, because successful HTTP\ndelivery can coexist with a broken mapping or detection.`,\n },\n {\n managedPath: 'security-and-audit/operate-siem.md',\n unitRef: 'technical-documentation:unit/operate-and-troubleshoot-siem-delivery',\n sourceRefs: [\n 'saas-technical-doc:engine-content/operate-and-troubleshoot-siem-delivery',\n 'source:consumer-fact:organization-siem-export',\n ],\n 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.`,\n },\n {\n managedPath: 'security-and-audit/protect-evidence.md',\n unitRef: 'technical-documentation:unit/protect-and-retain-audit-evidence',\n sourceRefs: ['saas-technical-doc:engine-content/protect-and-retain-audit-evidence'],\n markdown: `# Protect and retain audit evidence\n\nAudit evidence can contain identities, IP addresses, device context, role\nchanges and event-specific business identifiers. Its security value does not\nmake every copy safe or every reader appropriate.\n\n| Before you disclose or retain a copy | Successful result |\n| --- | --- |\n| Know the investigation purpose, evidence owner, authorized readers, retention rule and deletion date | The smallest useful evidence remains traceable and protected without creating an indefinite uncontrolled copy |\n\n~~~mermaid\nflowchart LR\n accTitle: Keep the authoritative audit trail separate from controlled copies\n accDescr: The application retains the immutable source audit row. An investigator may create a bounded JSON copy, SIEM delivery may create an operational monitoring copy, and archival may create a durable retention copy. Each downstream copy needs its own access, integrity, retention and deletion controls.\n source[\"Authoritative application audit row\"] --> review[\"In-product investigation\"]\n source --> bounded[\"Bounded JSON export\"]\n source --> siem[\"Organization SIEM copy\"]\n source --> archive[\"Durable archive copy\"]\n bounded --> controls[\"Named owner, access and deletion rule\"]\n siem --> controls\n archive --> controls\n~~~\n\nThe application audit row remains the source record. An exported file, SIEM\nevent or archive object is a separate copy with a separate custody lifecycle;\none copy's retention or deletion setting does not silently govern the others.\n\n## Know which copy you are handling\n\n| Evidence location | Primary purpose | Control to record |\n| --- | --- | --- |\n| Application audit trail | Authoritative investigation and access-review record | Who may search or export the organization scope |\n| Bounded JSON export | Small approved investigation or compliance review | Purpose, filters, recipient, protected location and deletion date |\n| SIEM destination | Continuous detection, correlation and operational response | Receiver access, delivery health, downstream retention and incident ownership |\n| Durable archive | Long-term governed retention | Retention basis, integrity checks, restoration procedure and legal-hold handling |\n\n## Preserve integrity and minimize disclosure\n\n- Keep event ID, timestamp, actor classification, organization, outcome and\n correlation fields unchanged.\n- Never add a credential or secret to event data, a support ticket or a SIEM rule.\n- Share the smallest time range and field set needed for the investigation.\n- Separate security evidence from operational logs and business history; each\n has a different purpose and access policy.\n- Record who exported or disclosed evidence and the approved reason.\n\nWhen a ticket or report needs only a few events, attach a redacted subset and\nretain a reference to the protected source copy. Do not edit the source evidence\nto make it easier to read. Explain redactions separately so another authorized\nreviewer can reproduce the selection.\n\n## Apply retention to every copy\n\nAudit rows are immutable: the resource exposes no update or delete operation.\nWhen archival is configured, records older than the archival horizon are copied\nto durable file storage; the primary audit rows are not deleted. When no\narchival horizon is configured, the primary store retains them indefinitely.\nProduction archival cannot be configured below one year.\n\nBefore retaining evidence, answer:\n\n1. Which policy, investigation, legal hold or regulatory purpose requires it?\n2. Which copy is authoritative for this use?\n3. Who owns access approval and periodic review?\n4. When may the copy be deleted, and who verifies deletion?\n5. How will an authorized reviewer verify that identifiers and timestamps were\n not changed?\n\n> **Archival is not deletion from the primary audit trail.** It creates another\n> durable copy after the configured horizon. Plan access, restoration and final\n> disposition for that copy explicitly.\n\n## Treat optional context carefully\n\nCorrelation ID connects events from one request to application logs and errors.\nClient-instance ID may connect activity across sessions only when the application\nhas explicitly enabled that context. Its absence is not a collection failure.\nFrontend service name may be absent for jobs, scheduled work and internal\noperations.\n\nApply the organization's retention, legal-hold, privacy and incident-response\npolicy to every exported or downstream copy. A SIEM retention rule does not\nchange the application's authoritative audit retention.\n\n## Before closing the evidence task\n\n- confirm the organization, environment, time range and event count;\n- preserve event and correlation identifiers unchanged;\n- record the evidence owner, approved recipients and purpose;\n- confirm the protected storage location and deletion or legal-hold rule;\n- remove temporary local copies and ticket attachments that are no longer\n required;\n- keep credentials and unrelated personal data out of the evidence package.`,\n },\n {\n managedPath: 'billing-and-subscriptions/billing.md',\n unitRef: 'technical-documentation:unit/billing',\n sourceRefs: [\n 'saas-technical-doc:engine-content/billing',\n 'source:consumer-fact:billing-lifecycle',\n ],\n markdown: `# Billing and subscriptions\n\nUse this section when you are responsible for an organization's plan, invoices,\nusage or access after a billing change. You do not need to know which billing\nprovider the application uses. You do need to distinguish three records:\n\n- the **product and price** describe what can be bought and on which terms;\n- the **subscription** records the current recurring relationship;\n- the application's **billing-derived access** records which features and limits\n the current subscription actually grants.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Know the organization being billed, who approved the commercial decision, the current product and the application access expected afterwards | The intended billing record reaches a known state, the resulting access is verified in the same organization, and payment evidence remains protected |\n\n{{CONSUMER_FACT:source:consumer-fact:billing-lifecycle#markdown}}\n\n## Keep the four billing views separate\n\n| View | Question it answers | Do not use it as proof of |\n| --- | --- | --- |\n| Product and price | What is offered, at what amount and interval, with which intended grants? | A purchase or active access |\n| Checkout or billing portal | Where are payment details, tax information and provider documents handled? | The final application subscription state |\n| Subscription and invoice summary | What recurring relationship and payment evidence did the application record? | Every feature currently available to the organization |\n| Resolved application access | Which features and limits can the organization actually use now? | Why that access exists without checking billing and other allowed sources |\n\nFor organization billing, the standard management operations accept\n**Organization Owner** and **Organization Admin** authority. A custom role may\ninherit effective authority in an application-specific role graph; review\n[Roles and permissions](/user-administration/roles-and-permissions) and the\nexact operation contract rather than granting a broad role merely to expose the\nBilling area.\n\n~~~mermaid\nflowchart LR\n accTitle: From a billing decision to usable application access\n accDescr: An authorized administrator selects a product and price, completes hosted checkout, waits for verified billing state, then confirms the subscription and billing-derived access in the application. Invoice and usage records remain separate evidence.\n choice[\"Choose product, price and billed scope\"] --> checkout[\"Complete hosted checkout\"]\n checkout --> verify[\"Application verifies billing result\"]\n verify --> subscription[\"Subscription state is updated\"]\n subscription --> access[\"Features and limits are recomputed\"]\n verify --> invoice[\"Invoice and payment state is recorded\"]\n usage[\"Metered application usage\"] --> invoice\n~~~\n\nThe important boundary is after checkout: **returning to the application is not\nproof that access changed**. Read the current subscription and verify the feature\nor limit you expected before telling people the change is complete.\n\nThe diagram has two evidence branches for a reason. Invoice/payment state\nexplains the commercial event, while subscription state drives the billing\naccess recomputation. A paid invoice and an unavailable feature can therefore\nboth be true during a mismatch that still needs reconciliation.\n\n## Choose the task you need\n\n| Your task | Start here | You are finished when |\n| --- | --- | --- |\n| Decide what to buy | [Understand plans, prices and access](/billing-and-subscriptions/plans-and-access) | The billed scope, price terms and expected access are explicit before approval |\n| Create the recurring relationship | [Start a subscription](/billing-and-subscriptions/start-subscription) | The application records Active or Trialing state and the intended access works |\n| Upgrade, downgrade, add capacity or end access | [Change, resume or end a subscription](/billing-and-subscriptions/change-or-end-subscription) | Effective timing, charge/credit and access consequences match the approved decision |\n| Review a charge, payment state, document or measured quantity | [Billing records and usage](/billing-and-subscriptions/billing-records) | The question is routed to its owning record and matched to the correct scope and period |\n| Resolve a mismatch | [Reconcile billing and application access](/billing-and-subscriptions/reconcile-access) | Provider evidence, application records and the original application action agree |\n| Recover from an unclear result | [Troubleshoot a billing change](/billing-and-subscriptions/troubleshoot) | The failing layer is identified without a duplicate purchase or hidden access grant |\n\n## Close every billing task with evidence\n\nRetain the billed organization, product/price identity, subscription or invoice\nidentifier, observed state, effective period, approval reference and correlation\ninformation needed for support. Do not retain card details, payment-method data,\nprovider secrets, complete invoice documents or capability-style invoice URLs in\nordinary logs and tickets.`,\n },\n {\n managedPath: 'billing-and-subscriptions/plans-and-access.md',\n unitRef: 'technical-documentation:unit/understand-billing-plans-and-access',\n sourceRefs: [\n 'saas-technical-doc:engine-content/understand-billing-plans-and-access',\n 'source:consumer-fact:billing-lifecycle',\n ],\n markdown: `# Understand plans, prices and access\n\nBefore approving a purchase, identify **what is being bought, who will be\nbilled, when the charge repeats and which application access should change**.\nThe current Billing area is authoritative for the products and prices offered by\nthis application. The supported product-kind inventory is not proof that every\nkind is offered here.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Have the intended organization, business owner, expected users or workload, required features/capacity and approved spending boundary | One current product and price satisfy the outcome without unnecessary capacity, and the expected access can be verified after purchase |\n\n## Start from the work, not the plan name\n\nWrite down the outcome before comparing offers—for example, “the Support\norganization needs ten additional automated runs this month.” Then ask:\n\n- Is the requirement a continuing base capability, optional recurring capacity,\n measured use, a one-time item or prepaid credits?\n- Does the purchase belong to this organization, and will everybody who needs\n it operate in that same scope?\n- Which exact feature or limit should change, and what current application\n action will prove it?\n- When should the commercial and access change take effect?\n- Who owns renewal, usage review and cancellation?\n\n{{CONSUMER_FACT:source:consumer-fact:billing-lifecycle#productTypesMarkdown}}\n\nThe table lists product kinds the application can support. Only products and\nprices shown in this application's current Billing area are purchasable offers.\nDo not ask support to create a missing kind from this list.\n\n## Understand how quantity changes the amount\n\nThe product kind explains **what you are buying**. The pricing model explains\n**how the selected quantity becomes a charge**. Do not use the words “tiered”\nand “graduated” interchangeably: they produce different totals.\n\n{{CONSUMER_FACT:source:consumer-fact:billing-lifecycle#pricingModelsMarkdown}}\n\n### Worked example: 240 units\n\nThe following numbers are illustrative, not an offer from this application.\nThey show why the pricing model must be recorded with the amount:\n\n| Model | Illustrative terms | Result for 240 units |\n| --- | --- | --- |\n| Flat | €100 for the line item | €100 |\n| Per unit | €0.50 per unit | 240 × €0.50 = €120 |\n| Volume tiered | Up to 100 at €0.50; above 100 at €0.40 for all units | 240 × €0.40 = €96 |\n| Graduated | First 100 at €0.50; remaining units at €0.40 | (100 × €0.50) + (140 × €0.40) = €106 |\n| Package | €10 per block of 25, rounded up | 10 packages × €10 = €100 |\n\nFor a tiered or package offer, keep the tier boundaries, flat additions and\npackage size with the approval. A headline unit price is not enough to\nreconstruct the expected invoice.\n\n## Read a price as a complete offer\n\nCheck the product name and description together with:\n\n- the billed scope—usually an organization, or a person only when the\n application explicitly offers personal billing;\n- currency and amount;\n- monthly or yearly interval for recurring prices;\n- whether tax is included in the displayed amount or added at checkout;\n- trial duration and whether a payment method is required;\n- included features, capacity limits and any metered usage;\n- promotion eligibility and the date on which the offer expires.\n\nFor a recurring price, read both the interval and its count. “Month” with an\ninterval count of 3 means every three months, not monthly:\n\n{{CONSUMER_FACT:source:consumer-fact:billing-lifecycle#billingIntervalsMarkdown}}\n\nCurrency codes should be interpreted using the maintained\n[ISO 4217 currency list](https://www.iso.org/iso-4217-currency-codes.html).\nThe displayed currency does not determine whether tax is included:\n\n{{CONSUMER_FACT:source:consumer-fact:billing-lifecycle#taxDisplayModesMarkdown}}\n\nIf the hosted billing screen is Stripe, its maintained\n[tax-behaviour guide](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior)\nexplains the provider-side inclusive/exclusive distinction. The application\noffer and checkout total remain the evidence for this purchase.\n\nAn **add-on** changes the same subscription without replacing its primary plan.\nA **credit pack** adds a consumable balance. Neither should be described as a\nplan upgrade unless that is what the product screen actually presents.\n\n## Trace an offer to application access\n\n~~~mermaid\nflowchart TD\n accTitle: Evaluate a billing offer from commercial terms to application access\n accDescr: The administrator starts with a required business outcome, chooses an offered product and price for one billed scope, reviews trial, timing and usage terms, identifies the promised feature or limit, then records how that access will be verified after purchase.\n outcome[\"Name the required business outcome\"] --> scope[\"Confirm billed organization or person\"]\n scope --> offer[\"Choose one currently offered product and price\"]\n offer --> terms[\"Review interval, tax, trial, quantity and promotion\"]\n terms --> grants[\"Identify expected features, limits or credits\"]\n grants --> proof[\"Define one application action that proves access\"]\n proof --> approval[\"Record approval and lifecycle owner\"]\n~~~\n\nThe important handoff is from **grants** to **proof**. A product description can\nstate what should be included; the original application action verifies what is\nactually usable after the billing state is processed.\n\n## Understand how access is assembled\n\nOne active plan supplies the base features and limits. Active add-ons can add\nfeatures or capacity. The application recomputes that billing-derived access\nfrom subscriptions in **Active** or **Trialing** state. Other subscription states\ndo not contribute billing-derived access.\n\nManual or broader-scope access can also exist. A feature remaining available\nafter a downgrade therefore does not, by itself, prove that billing\nreconciliation failed. Compare the expected product grants with the resolved\napplication access for the billed scope.\n\nBase-plan and add-on limits can combine according to the offered product policy:\nan add-on may add capacity or establish a higher limit. “Unlimited” capacity\nremains unlimited when combined. Do not calculate the final limit from marketing\nlabels alone; read the resolved limit in the billed scope.\n\n{{CONSUMER_FACT:source:consumer-fact:billing-lifecycle#limitGrantModesMarkdown}}\n\nFor example, a plan can establish 50 scheduled runs, while an add-on adds 20.\nThe expected result is 70. If instead the add-on establishes a limit of 100,\nthe expected result is 100—not 150. Verify the resolved value after purchase,\nbecause access can also come from a broader scope or an approved manual source.\n\n## Treat a promotion as conditional until checkout accepts it\n\n{{CONSUMER_FACT:source:consumer-fact:billing-lifecycle#promotionVocabularyMarkdown}}\n\nA promotion shown in Billing can still be refused for the selected purchase.\nBefore relying on it, verify its validity dates, remaining redemptions, eligible\nproducts, discount currency when fixed, and duration. The checkout result is the\npositive proof; visibility in a list is only a reason to evaluate it.\n\n## Approve with a reviewable record\n\nRecord the selected product and price, currency, interval, quantity, tax/trial\nterms, expected effective date, billed scope, expected grants and the person who\napproved them. Keep payment instruments and provider credentials out of that\nrecord. Continue to [Start a subscription](/billing-and-subscriptions/start-subscription)\nonly after the expected application proof is clear.`,\n },\n {\n managedPath: 'billing-and-subscriptions/start-subscription.md',\n unitRef: 'technical-documentation:unit/start-billing-subscription',\n sourceRefs: [\n 'saas-technical-doc:engine-content/start-billing-subscription',\n ],\n 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.`,\n },\n {\n managedPath: 'billing-and-subscriptions/change-or-end-subscription.md',\n unitRef: 'technical-documentation:unit/change-or-end-billing-subscription',\n sourceRefs: [\n 'saas-technical-doc:engine-content/change-or-end-billing-subscription',\n 'source:consumer-fact:billing-lifecycle',\n ],\n 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.`,\n },\n {\n managedPath: 'billing-and-subscriptions/billing-records.md',\n unitRef: 'technical-documentation:unit/billing-records-and-usage',\n sourceRefs: ['saas-technical-doc:engine-content/billing-records-and-usage'],\n markdown: `# Billing records and usage\n\nUse this journey when you need to explain **what was bought, what was charged,\nwhat was measured, or why application access differs from the commercial\nrecord**. Those questions use related records, but they do not have the same\nauthority.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Know the environment, organization, product, billing period and the exact question being investigated | The question is answered from the record that owns it, then checked against the adjacent records without exposing payment data or duplicating a charge |\n\n## Choose the record that owns the answer\n\n| Question | Start with | Then compare |\n| --- | --- | --- |\n| Which recurring product is current? | Subscription items, status and period | Product/price offer and resolved access |\n| Was a charge created or paid? | Application invoice summary | Complete document in the authenticated provider portal |\n| Why is the invoice quantity different? | Local usage rows for the same period | Reported state and provider meter result |\n| Why is a feature unavailable after payment? | Current subscription and resolved access | Invoice/payment evidence only if the subscription state requires it |\n\n~~~mermaid\nflowchart LR\n accTitle: Use each billing record for the question it owns\n accDescr: The product and price describe the offer. The subscription records the recurring relationship and drives billing-derived access. Metered activity becomes local usage records and is reported to the provider. The provider creates the invoice; the application stores a safe summary while the complete document and payment methods remain in the authenticated provider portal.\n offer[\"Product and price\"] --> subscription[\"Subscription\"]\n subscription --> access[\"Billing-derived access\"]\n activity[\"Metered activity\"] --> usage[\"Local usage records\"]\n usage --> provider[\"Provider meter\"]\n subscription --> invoice[\"Provider invoice\"]\n provider --> invoice\n invoice --> summary[\"Application invoice summary\"]\n invoice --> portal[\"Authenticated provider portal\"]\n~~~\n\nThe useful boundary is between **operational summary** and **protected source\ndocument**. The application exposes enough invoice state and total information\nfor reconciliation, but complete tax documents and payment methods stay behind\nthe provider's authenticated portal. Usage remains separately traceable so a\nquantity can be explained before it becomes an invoice line.\n\n## Choose your task\n\n- [Manage invoices and payment details](/billing-and-subscriptions/invoices-and-payments)\n when the question concerns payment state, currency, tax or the complete invoice.\n- [Understand metered usage](/billing-and-subscriptions/metered-usage) when the\n question concerns measured quantity, reporting delay or a provider meter.\n- [Reconcile billing and application access](/billing-and-subscriptions/reconcile-access)\n when the commercial record is correct but the application outcome is not.\n- [Troubleshoot a billing change](/billing-and-subscriptions/troubleshoot) when\n the first durable record or failing boundary is still unclear.\n\nRetain identifiers, totals, states, periods and correlation evidence. Do not\ncopy card data, payment-method details, complete invoice documents, temporary\nportal URLs or personal data from usage metadata into ordinary tickets.`,\n },\n {\n managedPath: 'billing-and-subscriptions/invoices-and-payments.md',\n unitRef: 'technical-documentation:unit/manage-invoices-and-payments',\n sourceRefs: [\n 'saas-technical-doc:engine-content/manage-invoices-and-payments',\n 'source:consumer-fact:billing-lifecycle',\n ],\n markdown: `# Manage invoices and payment details\n\nAn invoice is evidence of a charge, not the subscription itself. The application\nstores a small invoice summary—state, total and timestamps—while the billing\nprovider keeps the complete tax document and payment methods behind its\nauthenticated portal.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Know the billed organization, product, billing period and question being investigated; use an authorized billing administrator for provider documents | The application summary and provider document refer to the same charge, payment state and period without exposing payment data |\n\n## Know which record answers which question\n\n~~~mermaid\nflowchart LR\n accTitle: Separate the application invoice summary from the protected provider document\n accDescr: A subscription defines the recurring product and billing period. The provider creates an invoice and owns payment methods and the complete tax document. The application retains a safe status and total summary for operational review, while an authorized administrator opens the authenticated portal for the full document or payment change.\n subscription[\"Subscription and billing period\"] --> invoice[\"Provider invoice\"]\n invoice --> summary[\"Application invoice summary\"]\n invoice --> portal[\"Authenticated billing portal\"]\n portal --> document[\"Complete invoice or receipt\"]\n portal --> payment[\"Payment methods and billing details\"]\n~~~\n\nThe application summary is designed for status checks and reconciliation. It is\nnot a replacement for the provider's full tax document.\n\n{{CONSUMER_FACT:source:consumer-fact:billing-lifecycle#invoiceStatusesMarkdown}}\n\nOpen complete invoice documents through the authenticated billing portal. Direct\nprovider document URLs are deliberately not exposed in the application API:\nthey can act like bearer links to documents containing names and billing\naddresses.\n\nUse the provider portal only from the application's Billing area and return to\nthe intended environment afterwards. Do not copy a complete invoice into an\nordinary ticket when its identifier, total, currency, period and state are\nsufficient to investigate.\n\nIf the portal identifies itself as Stripe, use Stripe's maintained\n[customer-portal guide](https://docs.stripe.com/customer-management/integrate-customer-portal)\nto understand the provider handoff and its\n[Hosted Invoice Page guide](https://docs.stripe.com/invoicing/hosted-invoice-page)\nto understand the complete document surface. Always open a fresh portal session\nfrom the application; do not preserve or redistribute its temporary URL.\n\n## Read payment and subscription state together\n\n- An **Open** or **Uncollectible** invoice explains a payment problem, but the\n current subscription state determines whether billing-derived access remains.\n- A **Paid** invoice proves settlement of that invoice; still verify that the\n corresponding subscription and access update reached the intended scope.\n- A **Void** invoice should not be treated as a successful payment or as a new\n entitlement.\n\nAn invoice can change after it is first created—for example from Draft to Open\nor Paid. Record the state and observation time when using it as evidence. The\nlatest application summary is appropriate for operational review; the provider\nportal owns the complete document.\n\n## Interpret currency, tax and payment state separately\n\n{{CONSUMER_FACT:source:consumer-fact:billing-lifecycle#taxDisplayModesMarkdown}}\n\nInclusive or exclusive describes the **displayed price**. It does not prove the\ntax rate, jurisdiction, payment success or final amount. Compare the invoice\ncurrency, subtotal, tax, total and period with the approved offer and the\nprovider document. For an unfamiliar currency code, use the\n[ISO 4217 currency list](https://www.iso.org/iso-4217-currency-codes.html).\n\nWhen the invoice is Open or Uncollectible, an authorized administrator should\nopen Billing, enter the authenticated provider portal and review the available\npayment action. Do not ask the person to send card numbers, bank details or a\nscreenshot of the payment instrument to application support.\n\n### Example: a paid invoice but unchanged access\n\nA Paid invoice proves that **that invoice** was settled. It does not prove that\nthe application processed the corresponding subscription update or recomputed\naccess. Confirm the subscription is Active or Trialing, then repeat the\napplication action that should now be available. If that action still fails,\ncontinue with [Reconcile billing and application access](/billing-and-subscriptions/reconcile-access).\n\n## Protect financial evidence\n\nInvoice summaries remain financial history even when the billed scope is later\nretired. Limit access to administrators who need it, keep exports in protected\nstorage, and apply the organization's retention and legal-hold rules. Retain\nthe invoice identifier, currency, total, state, period and observation time in\nordinary support evidence—not the complete document or payment details.`,\n },\n {\n managedPath: 'billing-and-subscriptions/metered-usage.md',\n unitRef: 'technical-documentation:unit/understand-metered-usage',\n sourceRefs: [\n 'saas-technical-doc:engine-content/understand-metered-usage',\n 'source:consumer-fact:billing-lifecycle',\n ],\n 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.`,\n },\n {\n managedPath: 'billing-and-subscriptions/reconcile-access.md',\n unitRef: 'technical-documentation:unit/reconcile-billing-and-access',\n sourceRefs: [\n 'saas-technical-doc:engine-content/reconcile-billing-and-access',\n 'source:consumer-fact:billing-lifecycle',\n ],\n markdown: `# Reconcile billing and application access\n\nUse reconciliation when the provider, the application subscription and the\nperson's visible access do not tell the same story. Keep those layers separate;\nchanging a role to conceal a billing problem creates a second access problem.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Have the environment, billed organization, subscription and invoice identities, expected product grants, original application action and approximate change time | The first inconsistent layer is identified, repaired through its normal workflow and verified against current application state without a duplicate charge or unrelated access grant |\n\n{{CONSUMER_FACT:source:consumer-fact:billing-lifecycle#subscriptionStatusesMarkdown}}\n\n## Name the layer that disagrees\n\n| Layer | Evidence to read | Typical question |\n| --- | --- | --- |\n| Commercial offer | Current product, price, quantity and behavior policy shown by the application | Was the approved item actually offered for this scope? |\n| Provider transaction | Authenticated checkout/portal and invoice evidence | Did the provider complete, refuse or leave payment incomplete? |\n| Application billing state | Subscription items, status, period dates, invoice summary and usage reporting state | Did the verified result reach the intended billing account? |\n| Billing-derived access | Product grants and resolved feature/limit in the billed scope | Did the application recompute the access that this state should contribute? |\n| Original user action | The operation the person or workload tried to perform | Is the intended outcome now genuinely usable? |\n\nMove down the table in order. A role change at the final layer cannot repair an\nincomplete provider transaction, and a paid invoice does not by itself prove\nthat the application's subscription or feature state was updated.\n\n~~~mermaid\nflowchart TD\n accTitle: Reconcile a billing change from scope to entitlement\n accDescr: The reviewer confirms the billed scope, reads the application subscription and invoice, checks whether the subscription state contributes billing access, compares product grants with resolved access, and then repairs the failing layer.\n symptom[\"Expected access differs from visible access\"] --> scope[\"Confirm billed organization or person\"]\n scope --> subscription[\"Read current application subscription\"]\n subscription --> state{\"Active or Trialing?\"}\n state -->|No| payment[\"Inspect invoice and payment state\"]\n state -->|Yes| grants[\"Compare plan and add-on grants\"]\n grants --> resolved[\"Check resolved feature and limit\"]\n payment --> repair[\"Repair billing or wait for verified update\"]\n resolved --> repair\n repair --> verify[\"Repeat the original application action\"]\n~~~\n\nNotice that the flow checks **Active or Trialing** before comparing grants.\nThose are the only maintained subscription states that contribute billing-\nderived access. Payment repair belongs before feature repair when the\nsubscription is in another state.\n\n## Reconciliation checklist\n\n1. Confirm the environment and billed scope.\n2. Read the current application subscription; do not rely on a provider email\n or redirect.\n3. Verify its product items, status, period dates and cancellation flag.\n4. If payment is involved, match the invoice total, currency and state.\n5. Compare the plan and add-on grants with the resolved feature or limit.\n6. Repeat the original application operation to prove access, not merely the\n Billing screen.\n7. Record the final subscription state and the evidence used to close the case.\n\nWhere a change may still be processing, preserve the first attempt and allow a\nbounded observation window instead of opening a replacement checkout. Where a\nwrite returned no response, re-read current subscription state before deciding\nwhether a retry is safe.\n\nOnly Active and Trialing subscriptions contribute billing-derived access. A\nfeature can still come from another allowed source, and a finite application\nlimit can combine with plan and add-on limits. Explain the actual resolved\nresult instead of assuming one plan label owns all access.\n\n## Choose the repair by the failing layer\n\n- **Wrong scope or offer:** return to the intended organization and select a\n current product/price through the normal Billing journey.\n- **Incomplete or failed payment:** use the authenticated billing portal; do not\n send payment details to application support.\n- **Stale application subscription:** preserve transaction and correlation\n evidence for support rather than patching the subscription record.\n- **Correct subscription but wrong grants:** compare the product and add-on\n definitions with the resolved feature/limit; do not add a broad role as a\n substitute.\n- **Correct resolved access but failed action:** troubleshoot the operation's\n organization, role, resource visibility and request separately from billing.\n\nClose with the organization, original symptom, responsible layer, correction,\nfinal subscription/invoice state and the repeated application action. Exclude\ncard details, provider secrets and complete invoice documents.`,\n },\n {\n managedPath: 'billing-and-subscriptions/troubleshoot.md',\n unitRef: 'technical-documentation:unit/troubleshoot-billing-change',\n sourceRefs: [\n 'saas-technical-doc:engine-content/troubleshoot-billing-change',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations.md',\n unitRef: 'technical-documentation:unit/integrations',\n sourceRefs: ['saas-technical-doc:engine-content/integrations'],\n markdown: `# Integrations\n\nAn integration connects this application to another system so that people do\nnot have to copy information or repeat the same action by hand. Start with the\noutcome you need, then choose the smallest contract that can deliver it safely.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Name one business outcome, the source of truth, the organization affected, the acting person or workload and who owns failures | The chosen connection proves one bounded allowed outcome, one expected refusal and a recovery path that does not expose credentials or repeat a business effect |\n\n## Which integration should you choose?\n\n| You need to… | Use | Why |\n| --- | --- | --- |\n| Read or change application data on demand | [REST API](/integrations/rest-api) | Your system sends a request and receives an immediate response |\n| Build a workflow in n8n, Zapier or Make | [Automation platforms](/integrations/automation-platforms) | The platform calls the REST API or receives a published event |\n| React when the application publishes an event | The Webhooks section, when available below | The application pushes a signed delivery to your receiver |\n| Connect Cursor, Codex or Claude Code | The AI coding tools section, when available below | The client discovers MCP tools available to its authenticated identity |\n| Give another AI client callable tools or exchange agent tasks | The Agent integrations section below | MCP covers tools; A2A covers messages and task lifecycles |\n\nDo not choose a protocol because its name is familiar. Choose it because its\ninteraction model matches the business outcome. A scheduled REST poll is not a\nreplacement for an event when timeliness matters; a webhook is not a command\nchannel; an MCP tool call is not an A2A conversation.\n\n~~~mermaid\nflowchart TD\n accTitle: Choose an integration contract from the intended outcome\n accDescr: Immediate request and response work uses REST. Event notification uses webhooks. Tool discovery and invocation uses MCP. Agent conversations and tasks use A2A.\n outcome[\"What must the other system accomplish?\"] --> immediate{\"Immediate request and response?\"}\n immediate -->|Yes| rest[\"REST API\"]\n immediate -->|No| event{\"React to an application event?\"}\n event -->|Yes| webhook[\"Webhook\"]\n event -->|No| agent{\"AI or agent interaction?\"}\n agent -->|Call advertised tools| mcp[\"MCP\"]\n agent -->|Exchange messages and tasks| a2a[\"A2A\"]\n~~~\n\nThe diagram is a starting point, not a permission decision. The identity used\nby the integration still needs access to the intended organization, resources\nand operations.\n\n## Keep the source of truth explicit\n\nDecide which system owns the final fact before writing synchronization logic.\nREST can retrieve or change current application state; a webhook announces that\nan event occurred; MCP invokes an advertised operation; A2A carries a message or\ntask. None of those contracts automatically makes the receiving copy\nauthoritative.\n\nAfter a timeout, duplicate or conflicting change, reconcile against the system\nthat owns the fact. If ownership is shared or unclear, define a human decision\npath rather than letting the last retry silently win.\n\n## Before you connect anything\n\n- Name the business outcome and the system that owns the authoritative state.\n- Use a separate identity and credential for each deployed workload.\n- Begin in a non-production organization with the least privilege required.\n- Decide how you will reconcile timeouts, duplicates and partially completed work.\n- Record correlation information without copying credentials or restricted data.\n\n## Prove the boundary before production\n\nStart with a harmless action whose correct result a person can recognize. Prove\nthe intended environment, identity, organization and response shape. Then prove\none expected refusal: another organization, an unavailable operation, an\ninvalid signature or insufficient authority must remain blocked.\n\nOnly after those checks should you add a mutation, automatic retry, schedule or\nproduction volume. For a state-changing path, deliberately simulate a lost\nresponse and show how authoritative state is read before another attempt.\n\nRetain the integration owner, deployed workload, non-secret credential\nidentifier, environment, organization, operation or event identity, outcome and\ncorrelation evidence. Define how the credential is rotated or revoked and who\nreceives an alert when the business result cannot be reconciled.\n\nIf you are building a new connection, begin with [Create your own integration](/integrations/create-your-own-integration). The API reference supplies exact paths and schemas after you have chosen the correct journey.`,\n },\n {\n managedPath: 'integrations/automation-platforms.md',\n unitRef: 'technical-documentation:unit/automation-platforms',\n sourceRefs: ['saas-technical-doc:engine-content/automation-platforms'],\n markdown: `# Automation platforms\n\nUse an automation platform when a business process must move information or\nstart work across systems without requiring a custom deployed service. This\nsection covers **n8n**, **Zapier** and **Make**. The application does not need a\nplatform-specific connector: each platform can call the published REST API,\nand it can receive application webhooks when a Webhooks section is available.\n\n## Start from the business event\n\nDescribe the automation in one sentence before opening the workflow editor:\n“When an approved record changes, create or update its counterpart in the\nreporting system.” That sentence identifies the trigger, the intended effect\nand the system that owns the final state.\n\n| The work starts when… | Begin with | Why |\n| --- | --- | --- |\n| A schedule, form or another system produces input | An authenticated REST request | The workflow controls when the application is read or changed |\n| This application publishes a relevant event | A webhook receiver | The workflow starts from the event instead of repeatedly polling |\n| A person presses a workflow button | A safe read, followed by an explicit write | The person can confirm scope before a change is made |\n\n~~~mermaid\nflowchart LR\n accTitle: Build an automation around one authoritative business outcome\n accDescr: A schedule, human action, or application event starts the workflow. The workflow validates the input, reads current application state, applies one intended effect, and records enough evidence to reconcile failures.\n trigger[\"Schedule, person or application event\"] --> validate[\"Validate input and organization\"]\n validate --> read[\"Read authoritative state\"]\n read --> decide{\"Change still required?\"}\n decide -->|No| finish[\"Record no change\"]\n decide -->|Yes| write[\"Apply one documented operation\"]\n write --> confirm[\"Confirm result and retain correlation\"]\n~~~\n\n## Choose your platform\n\n- [Connect n8n](/integrations/automation/n8n) when you want a visual workflow\n that can also be self-hosted and extended with technical nodes.\n- [Connect Zapier](/integrations/automation/zapier) when the business workflow\n already lives in Zaps and should use an API or webhook step.\n- [Connect Make](/integrations/automation/make) when you want to map a scenario\n visually and control HTTP request fields in a dedicated module.\n\n## Keep the first workflow deliberately small\n\nUse a dedicated credential for one environment and one workflow. Prove one\nread operation, then one write only if the business outcome requires it. Store\nthe credential in the platform's credential or connection store—not in a URL,\nordinary field, workflow name, execution note or shared screenshot.\n\nBefore enabling unattended runs, test invalid input, expired or revoked access,\ninsufficient permission, a timeout after a write and a duplicate trigger. The\nworkflow is production-ready only when an operator can determine whether the\nbusiness effect occurred without blindly repeating it.`,\n },\n {\n managedPath: 'integrations/automation/n8n.md',\n unitRef: 'technical-documentation:unit/connect-n8n',\n sourceRefs: [\n 'saas-technical-doc:engine-content/connect-n8n',\n 'source:consumer-fact:access-api-keys',\n ],\n markdown: `# Connect n8n\n\nUse n8n when a visual workflow should read or change information in this\napplication. There is no application-specific n8n node to install: the workflow\nuses n8n's standard **HTTP Request** node and the REST API published in this\ndocumentation.\n\nThis guide first builds a manual, read-only workflow. By the end, one click in\nn8n will call one authenticated operation and show recognizable application\ndata in the node output. Only then will you connect a trigger or add a write.\n\n> **If the application should start the workflow when something happens,**\n> complete the read-only connection first, then follow **Start from an\n> application event** below. Do not poll repeatedly when a published webhook\n> already represents the event you need.\n\n## What do you need before starting?\n\nAsk the application administrator or integration owner for:\n\n- the server origin shown in this application's API reference;\n- one authenticated **GET** operation and its complete path;\n- the non-production organization and known data you may use for the test;\n- a dedicated API key with only the role accepted by that operation; and\n- an owner who can revoke the key if the workflow is abandoned or exposed.\n\nUse [Create and store an API key](/access-and-identity/api-keys-create-and-store)\nif the credential has not been prepared. Keep n8n and the application in the\nsame environment throughout the test.\n\n## Build the first read-only workflow\n\n### 1. Create an explicit test trigger\n\nCreate a new workflow and keep it inactive. Add a **Manual Trigger** so that the\napplication is contacted only when you choose **Execute workflow**. Name the\nworkflow after the business result and environment—for example, “Read approved\nrecords — test”—not after the credential.\n\n### 2. Add the application request\n\nAdd an **HTTP Request** node after the trigger, then complete these fields from\nthe same API-reference operation:\n\n| n8n field | Value to use | How to verify it |\n| --- | --- | --- |\n| **Method** | The operation's documented HTTP method, initially **GET** | It matches the operation heading in the API reference |\n| **URL** | Server origin followed by the complete documented operation path | The origin appears once and the API path appears once |\n| **Authentication** | **Generic Credential Type**, then **Header Auth** | The key is stored as an n8n credential, not in the URL or workflow data |\n| **Send Headers** | Add **Accept** with value **application/json** | The request asks for the documented JSON response |\n| Query/path values | Only values required by the selected operation | Organization and resource identifiers are in the locations defined by the reference |\n\nWhen creating the **Header Auth** credential, use the maintained application\nheader contract below. Enter the header name and secret value in the credential\ndialog; do not construct them with an expression inside the node.\n\n~~~text\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#requestHeader}}\n~~~\n\nn8n's [HTTP Request node documentation](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.httprequest/)\nexplains the current node controls and generic credential options. If the\nlabels in your installed n8n version differ, use that documentation for the UI\nlocation while keeping the application request contract defined here.\n\n### 3. Execute and inspect the output\n\nSelect **Execute workflow**. The Manual Trigger and HTTP Request nodes should\ncomplete successfully, and the HTTP Request output panel should contain JSON\nmatching the response schema in the API reference.\n\nDo not treat a green node alone as proof. Confirm:\n\n- the output is from the intended application environment;\n- the data belongs to the intended organization;\n- the known record or collection result is present;\n- required fields have the types documented in the response schema; and\n- the API key is absent from the input, output and execution data panels.\n\n~~~mermaid\nsequenceDiagram\n accTitle: Build and prove the first n8n application workflow\n accDescr: An operator runs a manual trigger, n8n reads application data with a stored credential, the operator verifies the returned organization and schema, and only then replaces the trigger or adds a controlled business action.\n actor Operator\n participant n8n\n participant App as Application API\n Operator->>n8n: Execute inactive test workflow\n n8n->>App: Authenticated GET from HTTP Request node\n App-->>n8n: Documented JSON response\n n8n-->>Operator: Show node output\n Operator->>Operator: Verify environment, organization and known data\n Operator->>n8n: Add trigger or one controlled action\n~~~\n\nThe checkpoint in the diagram is the human verification after the first read.\nIt prevents an apparently successful workflow from being activated against the\nwrong organization or environment.\n\n## Prove the credential boundary\n\nCopy the HTTP Request node for this negative test. On the copy, temporarily set\nauthentication to **None** while leaving the URL and parameters unchanged. Run\nonly that node. The authenticated operation should return its documented\nauthentication refusal, normally **401**.\n\nDelete the unauthenticated copy after the test. If it returns the same protected\ndata as the authenticated node, stop: either the wrong operation was selected or\nthe access boundary needs investigation. Do not continue by adding a write.\n\n## Turn the read into a useful workflow\n\nConnect one decision or transformation step to the verified HTTP Request node.\nFor example, an **If** node can stop the workflow when the collection is empty,\nor a mapping step can select only the fields the next system is allowed to\nreceive.\n\nBefore adding a state-changing request, define all four items:\n\n1. the exact application state that should change;\n2. the condition that permits the change;\n3. the read operation that proves the final state; and\n4. what the workflow does when a write times out without a response.\n\nFor the first write, keep automatic retry disabled. Execute it once with known\ntest data, then read the target back. **A timeout is not proof that the write did\nnot happen**; use the read-back before deciding whether another request is\nneeded.\n\n## Start from an application event\n\nUse this path only when a Webhooks section is present in this documentation and\nthe application publishes the event you need.\n\n1. Add an n8n **Webhook** trigger and copy its **test URL**.\n2. Put n8n into test-listening mode.\n3. Configure a non-production application webhook endpoint for that URL.\n4. Send one controlled event and inspect the received request before mapping\n any fields.\n5. Verify the application's signature and deduplicate the delivery before a\n downstream action.\n6. Publish the n8n workflow, copy its **production URL**, and update the\n application endpoint. The temporary test URL is not the production address.\n\nFollow [Verify a webhook delivery](/integrations/webhooks/verify-delivery) for\nthe application trust boundary. n8n's\n[Webhook workflow guide](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.webhook/workflow-development/)\nexplains its test and production URL lifecycle.\n\n## When the workflow does not work\n\n| What you see in n8n | Most likely boundary | What to check next |\n| --- | --- | --- |\n| Connection or TLS error | Server/network | Confirm the API-reference server origin is reachable from the n8n host |\n| **401** response | Credential transport or lifecycle | Confirm Header Auth is selected and the stored key is active; never expose the value while checking |\n| **403** response | Role, organization or operation authority | Compare the key's approved role with the operation requirement |\n| **404** response | Identifier, organization scope or visibility | Confirm the target exists in the application and the path values came from the same environment |\n| Green node, wrong records | Scope or mapping | Stop the workflow and correct organization, filters or response mapping before adding downstream nodes |\n| Timeout after a write | Ambiguous business result | Read the application state; do not repeatedly execute the write node |\n| Webhook works only in test mode | URL lifecycle | Publish the workflow and configure the production URL |\n\nUse [Troubleshoot an API request](/integrations/rest/troubleshoot) when the\nHTTP response needs deeper diagnosis.\n\n## Before activating the workflow\n\n- Replace the Manual Trigger only after the read and negative test pass.\n- Keep the application key in n8n's credential store and restrict who can edit\n or use that credential.\n- Pin the server, organization and workflow purpose; do not make them silently\n depend on whichever item ran previously.\n- Validate required fields before a write and reject unexpected values.\n- Define failed-execution alerts, an accountable operator and a revocation\n procedure.\n- Test a revoked key, insufficient permission, invalid input and an unavailable\n dependency.\n- Retain non-secret operation, status, time and correlation evidence so an\n operator can reconcile the business result.`,\n },\n {\n managedPath: 'integrations/automation/zapier.md',\n unitRef: 'technical-documentation:unit/connect-zapier',\n sourceRefs: [\n 'saas-technical-doc:engine-content/connect-zapier',\n 'source:consumer-fact:access-api-keys',\n ],\n markdown: `# Connect Zapier\n\nUse Zapier when an existing Zap should read or change information in this\napplication. There is no application-specific Zapier connector to install. For\nan authenticated request, use **API by Zapier** so the API key lives in an app\nconnection instead of a visible Zap step.\n\nThis guide first creates one read-only action in an inactive Zap. You will test\nit with a known record, prove the authentication boundary, and only then connect\nthe action to a real trigger or add a write.\n\n> **Choose the other direction when the application starts the work.** If a\n> published application event should start the Zap, follow **Receive an\n> application event** below after the API connection proof.\n\n## Prepare one safe test\n\nBefore opening the Zap editor, collect:\n\n- the server origin and one authenticated **GET** operation from this\n application's API reference;\n- the non-production organization and one known record or collection result;\n- a dedicated API key with only the role accepted by that operation; and\n- an accountable owner for the Zap and credential.\n\nZapier's [current API-request comparison](https://help.zapier.com/hc/en-us/articles/44391646192397-Ways-to-make-API-requests-in-Zapier)\nexplains why **API by Zapier** is the appropriate choice for APIs that use an API\nkey: the credential is stored in an app connection. **Webhooks by Zapier** keeps\ncredentials in step fields and is not the preferred authenticated-request path.\n\n## Build the first read-only action\n\n### 1. Keep the Zap inactive\n\nCreate a Zap with the business outcome and environment in its name. Use a\ntrigger that can provide one controlled test item, but do not publish or turn on\nthe Zap yet.\n\n### 2. Add API by Zapier\n\nAdd **API by Zapier** as the action app and choose **API Request**. Create a new\napp connection for this application and environment. Configure the API key as a\nstatic header using the maintained application contract:\n\n~~~text\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#requestHeader}}\n~~~\n\nThe connection should own the secret. Do not copy the key into the request URL,\nZap name, mapped test data, notes or an ordinary step field.\n\n### 3. Enter the request from the API reference\n\nComplete the API Request action from one operation in the current reference:\n\n| Zapier field | Value to use | Verification |\n| --- | --- | --- |\n| Method | The documented method, initially **GET** | It matches the operation heading |\n| URL | Server origin plus the complete operation path | Origin and API prefix each appear once |\n| Headers | **Accept: application/json** plus connection-managed authentication | No API key is visible in the Zap step |\n| Parameters | Only required query/path values | Organization and record values are in the documented locations |\n| Body | Empty for the selected read unless the operation explicitly documents one | No response field was copied back as an invented request field |\n\n### 4. Test and inspect the action\n\nRun **Test step**. A useful connection proof has all of these results:\n\n- Zapier reports the operation's documented success status;\n- the output JSON matches the response schema;\n- the known record or collection result belongs to the intended organization;\n- the application key does not appear in the action input or output; and\n- later Zap steps can select the stable application identifier they need.\n\nDo not use a human-readable label as the reconciliation key when the response\nprovides a stable identifier.\n\n## Prove the request is protected\n\nAdd a temporary **Webhooks by Zapier — GET** action with the same read URL and\nparameters but **no authentication**. Test only that action. The protected\noperation should return its documented authentication refusal, normally\n**401**. Delete the temporary action after the proof.\n\nIf the unauthenticated action returns the protected data, stop. Confirm that you\nselected the intended authenticated operation before adding a write or enabling\nthe Zap.\n\n## Add one controlled business action\n\nPlace a **Filter** or equivalent decision step before any state-changing\nrequest. The filter should reject missing identifiers, the wrong organization\nand any business condition that does not justify the change.\n\nFor the first write:\n\n1. copy the exact method, schema and operation path from the API reference;\n2. test with one recognizable non-production record;\n3. keep automatic repetition disabled;\n4. read the record back from the application; and\n5. retain the returned application identifier for reconciliation.\n\n**A Zapier timeout is not proof that the application made no change.** Read the\nauthoritative record before replaying the action or the complete Zap.\n\n## Receive an application event\n\nUse this path only when a Webhooks section is published here and the application\npublishes the event you need.\n\n1. Add **Webhooks by Zapier — Catch Raw Hook** when the trigger must preserve\n the request needed for signature verification; otherwise use **Catch Hook**.\n2. Copy the unique hook URL and treat it as sensitive connection information.\n3. Configure one non-production application webhook endpoint for that URL.\n4. Send one controlled event and inspect the sample before mapping fields.\n5. Verify the application signature and deduplicate the delivery before any\n business effect.\n\nThe [official Catch Hook guide](https://help.zapier.com/hc/en-us/articles/8496288690317-Trigger-Zap-workflows-from-webhooks)\nexplains the trigger URL and sample lifecycle. If the selected Zapier trigger\ncannot preserve the raw signed request required by this application's\nverification contract, receive and verify the event in a controlled service,\nthen forward only the trusted fields the Zap needs.\n\n~~~mermaid\nflowchart TD\n accTitle: Choose a safe Zapier connection\n accDescr: A Zap either calls the application through a stored API connection or receives a verified application event. Both paths validate scope and input before mapping data into downstream actions.\n need{\"What starts the Zap?\"}\n need -->|Zap schedule or another app| request[\"Stored API connection\"]\n request --> api[\"Documented REST operation\"]\n need -->|Application event| hook[\"Catch Hook or verified receiver\"]\n hook --> verify[\"Verify and deduplicate event\"]\n api --> map[\"Validate and map result\"]\n verify --> map\n map --> downstream[\"One intended downstream effect\"]\n~~~\n\n## When a test or run fails\n\n| What Zapier shows | Check first | Safe next action |\n| --- | --- | --- |\n| Connection failure | Server origin, network and TLS | Repair reachability before changing the app connection |\n| **401** | API by Zapier connection and key lifecycle | Reconnect the correct active key without revealing it in the step |\n| **403** | Required role, organization and operation authority | Request only the approved missing authority; do not switch to an administrator credential |\n| **404** | Operation path, record identifier and organization visibility | Confirm the record in the application and the selected environment |\n| Test succeeds, later mapping is empty | Response schema and selected output path | Compare the test output with the current operation response before remapping |\n| Zap reports success, record is missing | Each step's input/output and authoritative application state | Locate the first divergent step; do not replay the entire Zap blindly |\n| Duplicate business effect | Trigger/delivery identity and reconciliation key | Stop the Zap and add deduplication before another event is accepted |\n\n## Before turning the Zap on\n\n- Pin the connection to one application environment and organization.\n- Confirm who can use the app connection and who owns revocation.\n- Test invalid input, a revoked key, insufficient permission and an unavailable\n dependency.\n- Define how a timeout after a write is reconciled before Zapier retries.\n- Prevent two trigger items or webhook deliveries from producing two business\n effects.\n- Send failure alerts with operation, time, status and correlation evidence—but\n no credential or unrestricted sensitive payload.`,\n },\n {\n managedPath: 'integrations/automation/make.md',\n unitRef: 'technical-documentation:unit/connect-make',\n sourceRefs: [\n 'saas-technical-doc:engine-content/connect-make',\n 'source:consumer-fact:access-api-keys',\n ],\n markdown: `# Connect Make\n\nUse Make when a visual scenario should read or change information in this\napplication. There is no application-specific Make app to install. The scenario\nuses **HTTP — Make a request** with a credential stored in a Make keychain.\n\nThis guide builds one read-only module in an inactive scenario, verifies its\noutput and access boundary, and only then adds a schedule, downstream module or\napplication webhook.\n\n## Prepare the connection proof\n\nCollect these values before opening the Scenario Builder:\n\n- the server origin and one authenticated **GET** operation from this\n application's API reference;\n- the intended non-production organization;\n- one record or collection result you can recognize;\n- a dedicated API key with only the role accepted by the operation; and\n- the person who owns the scenario and can revoke its credential.\n\n## Build the first read-only scenario\n\n### 1. Add the HTTP module\n\nCreate a scenario, keep scheduling **off**, and add **HTTP — Make a request**.\nName the scenario after its business result and environment rather than after\nthe credential.\n\n### 2. Store the credential\n\nIn the module's **Credentials** field, choose API-key authentication and create\na dedicated keychain. Put the complete application key in the key field, choose\nheader placement, and use **Authorization** as the parameter name. The resulting\nrequest must contain:\n\n~~~text\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#requestHeader}}\n~~~\n\nUse the dedicated credential field. Do not duplicate the key in ordinary\nheaders, query parameters, the scenario name, notes or mapped bundles.\n\n### 3. Configure the documented request\n\nComplete the remaining module fields from the same API-reference operation:\n\n| Make field | Value to use | Verification |\n| --- | --- | --- |\n| URL | Server origin plus the complete operation path | HTTPS, origin and API prefix each appear once |\n| Method | The documented method, initially **GET** | It matches the operation heading |\n| Headers | Add **Accept: application/json** | Authentication remains in **Credentials**, not duplicated here |\n| Query parameters | Only parameters accepted by the operation | Organization and record values are in documented locations |\n| Body content type | No body for the selected read unless documented | For later writes, choose the exact documented content type |\n| Parse response | **Yes** | Returned fields become available for mapping after a successful run |\n\nMake's [current HTTP app documentation](https://apps.make.com/http) defines the\nmodule fields, credential types, response parsing and pagination controls. Do\nnot select a pagination mode until the application's exact collection operation\ndocuments the matching contract.\n\n### 4. Run once and inspect the bundle\n\nSelect **Run once** and execute the module. A successful connection proof means:\n\n- the module returns the operation's documented success status;\n- the parsed output matches the documented response shape;\n- the known record or collection belongs to the intended organization;\n- the API key is absent from the module input/output bundles; and\n- the stable application identifier is available for later modules.\n\nDo not add mappings while the result belongs to the wrong environment or\norganization, even when the module is green.\n\n## Prove the authentication boundary\n\nClone the HTTP module for a temporary negative test. Remove **Credentials** from\nthe copy without adding an Authorization header, then run only that module. The\nprotected operation should return the documented authentication refusal,\nnormally **401**. Delete the unauthenticated copy after the test.\n\nIf it returns the protected data, stop and verify that the selected operation\nactually requires authentication before continuing.\n\n## Add one controlled change\n\nBefore adding a state-changing HTTP module, define the exact condition that\npermits it and add a Make filter that rejects missing identifiers, the wrong\norganization and incomplete source data.\n\nRun the first write once with a recognizable non-production record. Then read\nthe target back from the application. **A connection loss or timeout does not\nprove that the write failed**; reconcile current state before allowing Make to\nrepeat the module.\n\n## Receive an application event\n\nUse this path only when a Webhooks section is present here and the application\npublishes the event you need.\n\n1. Add **Webhooks — Custom webhook**, select **Add**, give the webhook a name,\n and copy the generated URL.\n2. In **Advanced settings**, enable **Get request headers** and **JSON\n pass-through** when required by the application's raw-body verification\n contract.\n3. Select **Run once** so Make listens for a controlled sample.\n4. Configure one non-production application webhook endpoint and send one known\n event.\n5. Verify the application signature and deduplicate the delivery before a\n downstream business action.\n\nMake's [current Webhooks documentation](https://apps.make.com/gateway) explains\nthe unique URL, **Run once**, data structures, request headers and JSON\npass-through controls. A generated Make data structure is an editing aid, not a\ntrust decision. If the module cannot preserve the exact signed request required\nby this application's verification contract, receive and verify it in a\ncontrolled service first, then forward only trusted fields to Make.\n\n~~~mermaid\nsequenceDiagram\n accTitle: Move a Make scenario from a controlled test to operation\n accDescr: The operator stores an API key in a Make keychain, proves one application read, optionally captures one verified webhook sample, maps only required values, then schedules or activates the scenario with failure handling.\n participant Operator\n participant Make\n participant App as Application\n Operator->>Make: Create API-key keychain\n Make->>App: Safe documented read\n App-->>Make: Parsed JSON response\n App->>Make: Optional controlled webhook event\n Operator->>Make: Validate mapping and error route\n Operator->>Make: Activate scenario\n~~~\n\n## When the scenario does not work\n\n| What Make shows | Check first | Safe next action |\n| --- | --- | --- |\n| Connection or TLS error | Server origin and reachability from Make | Repair the connection before changing the keychain |\n| **400** | Required values and mapped request body | Compare each submitted field with the current operation schema |\n| **401** | Keychain selection and key lifecycle | Attach the correct active keychain without exposing its value in headers |\n| **403** | Required role, organization and operation authority | Request only the approved missing authority; do not switch to an administrator key |\n| **404** | Operation path, identifier and organization visibility | Confirm the target and environment in the application |\n| Parsed field disappears | Raw response and current response schema | Correct the mapping after establishing whether the contract or selected path changed |\n| Timeout after a write | Authoritative application state | Read the target before repeating the module |\n| Webhook bundle lacks signed material | Request-header and JSON pass-through settings | Stop downstream actions until the verification boundary can be preserved |\n\n## Before scheduling or activating\n\n- Pin the scenario, keychain and webhook to one environment and organization.\n- Keep one credential per workload so it can be rotated or deactivated alone.\n- Add an error route that distinguishes invalid input, access refusal,\n throttling and unavailable dependencies.\n- Test a revoked key, insufficient permission, malformed input and a timeout\n after a controlled write.\n- Deduplicate triggers before producing a downstream business effect.\n- Retain application identifiers, status, time and correlation evidence—not\n credentials or unrestricted request/response bodies.`,\n },\n {\n managedPath: 'integrations/ai-coding-tools.md',\n unitRef: 'technical-documentation:unit/ai-coding-tools',\n sourceRefs: [\n 'saas-technical-doc:engine-content/ai-coding-tools',\n 'source:companion-projection:application-connection',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/ai-tools/cursor.md',\n unitRef: 'technical-documentation:unit/connect-cursor',\n sourceRefs: [\n 'saas-technical-doc:engine-content/connect-cursor',\n 'source:companion-projection:application-connection',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/ai-tools/codex.md',\n unitRef: 'technical-documentation:unit/connect-codex',\n sourceRefs: [\n 'saas-technical-doc:engine-content/connect-codex',\n 'source:companion-projection:application-connection',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/ai-tools/claude-code.md',\n unitRef: 'technical-documentation:unit/connect-claude-code',\n sourceRefs: [\n 'saas-technical-doc:engine-content/connect-claude-code',\n 'source:companion-projection:application-connection',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/agents.md',\n unitRef: 'technical-documentation:unit/agent-interoperability',\n sourceRefs: ['saas-technical-doc:engine-content/agent-interoperability'],\n markdown: `# Agent integrations\n\nUse an agent integration when software should choose or coordinate work through\nan AI-facing contract rather than through a fixed REST workflow. The application\ncan expose two different models:\n\n- **Model Context Protocol (MCP)** lets an AI client discover and call\n authorized application operations as tools.\n- **Agent-to-Agent (A2A)** lets a remote agent exchange messages and manage work\n that may continue as a task.\n\nThey use the application's identity and access boundaries, but they do not have\nthe same purpose, state or recovery model.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Name the business outcome, the person or workload authorizing it, the organization in scope, the maximum acceptable autonomy and the authoritative source used after uncertainty | The client uses the protocol that matches the work, sees only its authorized catalogue or agent, proves one harmless interaction and cannot repeat a state-changing effect merely because a response was lost |\n\n## Choose the interaction model\n\n| Question | MCP | A2A |\n| --- | --- | --- |\n| What does the client discover? | A caller-specific tool catalogue | An agent card describing the agent and its skills |\n| What is the primary interaction? | One tool invocation with structured arguments | A message that may produce a response or an asynchronous task |\n| What must be correlated? | Tool call, identity and application operation | Conversation context, task, agent instance and identity |\n| Where should you start? | The MCP connection guide, when this application publishes MCP tools | The A2A connection guide, when this application publishes A2A skills |\n\nChoose MCP when the desired work can be expressed as a known application\noperation with structured arguments and an immediate result. Choose A2A when\nthe caller needs a conversation, an agent-selected skill or a task identity that\ncan be read, streamed or cancelled later. Do not use A2A merely to wrap a fixed\nAPI call, and do not use MCP when the real operating requirement is a\nlong-running conversational task.\n\n~~~mermaid\nflowchart TD\n accTitle: Choose and constrain an application agent integration\n accDescr: An integration owner starts from the business outcome, chooses structured tool invocation or conversational task work, establishes the intended identity and organization, proves a harmless interaction, then adds bounded autonomy with authoritative reconciliation.\n outcome[\"Name one business outcome\"] --> mode{\"Known operation with immediate result?\"}\n mode -->|Yes| mcp[\"Use MCP tool discovery and invocation\"]\n mode -->|No, conversation or task| a2a[\"Use A2A message and task lifecycle\"]\n mcp --> identity[\"Bind one identity, audience and organization\"]\n a2a --> identity\n identity --> proof[\"Prove one harmless allowed action and one refusal\"]\n proof --> impact{\"State-changing or high impact?\"}\n impact -->|No| operate[\"Operate with bounded rate and evidence\"]\n impact -->|Yes| approval[\"Require approval and reconciliation rule\"]\n approval --> operate\n~~~\n\nIn both cases, a valid credential does not grant universal access. The active\norganization, roles, resource visibility, operation policy and any approval\nrequirement still apply.\n\nThe connection guides available below are generated from this application's\nown executable configuration. If one protocol is not configured, its guide is\nomitted instead of presenting a connection path that cannot work.\n\n## Choose the acting identity\n\nDecide whether the agent acts as a dedicated machine workload or on behalf of a\nperson. A machine identity is appropriate for scheduled or service-owned work;\na delegated identity is appropriate when a person knowingly authorizes the\nclient. Do not let a developer's administrator session become the production\ncredential for an unattended agent.\n\nKeep four values aligned throughout the connection:\n\n1. the application environment and server address;\n2. the selected MCP server or A2A agent instance, when a named instance is used;\n3. the credential audience and acting identity;\n4. the active organization and roles required for the intended work.\n\nA catalogue or agent card is discovery evidence, not an access grant. The\nspecific tool call, message or task operation still applies authorization and\nscope checks.\n\n## Set a safe autonomy boundary\n\nBegin with read-only work in one non-production organization. Add mutations\nonly after you have tested refusal, validation failure, timeout and an ambiguous\noutcome. Before repeating a state-changing action, read the authoritative state\nand determine whether the first attempt already applied.\n\nDefine the boundary explicitly:\n\n- which tools or agent skills may be used;\n- which organizations and resource types are in scope;\n- whether a person must approve a state-changing or high-impact step;\n- the maximum call or turn rate and spending/budget posture;\n- what result requires an authoritative read before another attempt;\n- who can disable the credential or client during an incident.\n\nTest at least one allowed read, one unavailable tool or skill, one insufficient-\nauthority refusal and one malformed input. For a mutation, test a lost or\nambiguous response in a safe scope and demonstrate reconciliation before\nallowing automatic repetition.\n\n## Separate model output from application truth\n\nTool results, agent messages and artifacts are inputs to the client. Validate\ntheir structured shape and treat any embedded instructions or links as\nuntrusted content. A model's statement that a change succeeded is not proof;\nread the authoritative application record and preserve the application-side\ncorrelation or audit evidence.\n\nKeep bearer and refresh credentials out of prompts, conversation transcripts,\ntool arguments and browser-accessible storage. Agent logs are useful diagnostic\nevidence, but they do not replace the application's authoritative audit trail.\n\n## Choose the next guide\n\n- **Connect an MCP client** — published in this section when the application\n exposes an MCP tool surface — for caller-specific tool discovery and\n structured application operations.\n- **Connect an A2A agent** — published in this section when the application\n exposes an A2A agent surface — for conversations and task lifecycle\n management.\n- [Create your own integration](/integrations/create-your-own-integration) when\n a deterministic REST or webhook workflow may be a better fit.`,\n },\n {\n managedPath: 'integrations/create-your-own-integration.md',\n unitRef: 'technical-documentation:unit/first-request',\n sourceRefs: [\n 'saas-technical-doc:engine-content/first-request',\n 'source:companion-projection:application-connection',\n 'source:consumer-fact:access-api-keys',\n ],\n 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 \\\n --url \"{{APPLICATION_CONNECTION_VALUE:baseUrl}}<documented-operation-path>\" \\\n {{CONSUMER_FACT:source:consumer-fact:access-api-keys#curlRequestHeader}} \\\n --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.`,\n },\n {\n managedPath: 'integrations/rest-api.md',\n unitRef: 'technical-documentation:unit/common-rest-api',\n sourceRefs: [\n 'saas-technical-doc:engine-content/common-rest-api',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/rest/conventions.md',\n unitRef: 'technical-documentation:unit/rest-api-conventions',\n sourceRefs: [\n 'saas-technical-doc:engine-content/rest-api-conventions',\n 'source:companion-projection:application-connection',\n 'source:consumer-fact:access-api-keys',\n 'source:consumer-fact:rest-conventions',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/rest/send-request.md',\n unitRef: 'technical-documentation:unit/send-api-request',\n sourceRefs: [\n 'saas-technical-doc:engine-content/send-api-request',\n 'source:companion-projection:application-connection',\n 'source:consumer-fact:access-api-keys',\n ],\n 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).`,\n },\n {\n managedPath: 'integrations/rest/read-collections.md',\n unitRef: 'technical-documentation:unit/work-with-api-collections',\n sourceRefs: [\n 'saas-technical-doc:engine-content/work-with-api-collections',\n 'source:consumer-fact:rest-conventions',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/rest/write-and-reconcile.md',\n unitRef: 'technical-documentation:unit/write-and-reconcile-api-changes',\n sourceRefs: [\n 'saas-technical-doc:engine-content/write-and-reconcile-api-changes',\n 'source:consumer-fact:rest-conventions',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/rest/troubleshoot.md',\n unitRef: 'technical-documentation:unit/troubleshoot-api-request',\n sourceRefs: [\n 'saas-technical-doc:engine-content/troubleshoot-api-request',\n 'source:consumer-fact:access-api-keys',\n 'source:consumer-fact:rest-conventions',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/webhooks.md',\n unitRef: 'technical-documentation:unit/webhooks',\n sourceRefs: [\n 'saas-technical-doc:engine-content/webhooks',\n 'source:companion-projection:application-integration',\n 'source:consumer-fact:outbound-webhooks',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/webhooks/configure-and-test.md',\n unitRef: 'technical-documentation:unit/configure-and-test-webhook-endpoint',\n sourceRefs: [\n 'saas-technical-doc:engine-content/configure-and-test-webhook-endpoint',\n 'source:consumer-fact:outbound-webhooks',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/webhooks/verify-delivery.md',\n unitRef: 'technical-documentation:unit/verify-webhook-delivery',\n sourceRefs: [\n 'saas-technical-doc:engine-content/verify-webhook-delivery',\n 'source:consumer-fact:outbound-webhooks',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/webhooks/operate-deliveries.md',\n unitRef: 'technical-documentation:unit/operate-webhook-deliveries',\n sourceRefs: [\n 'saas-technical-doc:engine-content/operate-webhook-deliveries',\n 'source:consumer-fact:outbound-webhooks',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/webhooks/troubleshoot.md',\n unitRef: 'technical-documentation:unit/troubleshoot-webhook-deliveries',\n sourceRefs: [\n 'saas-technical-doc:engine-content/troubleshoot-webhook-deliveries',\n 'source:consumer-fact:outbound-webhooks',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/mcp.md',\n unitRef: 'technical-documentation:unit/mcp-integrations',\n sourceRefs: [\n 'saas-technical-doc:engine-content/mcp-integrations',\n 'source:companion-projection:application-connection',\n 'source:companion-projection:application-integration',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/a2a.md',\n unitRef: 'technical-documentation:unit/a2a-integrations',\n sourceRefs: [\n 'saas-technical-doc:engine-content/a2a-integrations',\n 'source:companion-projection:application-connection',\n ],\n 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.`,\n },\n] as const;\n"]}
1
+ {"version":3,"file":"application-consumer-documentation-content.techdoc.js","sourceRoot":"","sources":["../../../../src/content/application-consumer-documentation-content.techdoc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,CAAC,MAAM,sDAAsD,GAAG;IACpE;QACE,WAAW,EAAE,gBAAgB;QAC7B,OAAO,EAAE,sDAAsD;QAC/D,UAAU,EAAE;YACV,2DAA2D;YAC3D,oDAAoD;SACrD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sUAkCwT;KACnU;IACD;QACE,WAAW,EAAE,kCAAkC;QAC/C,OAAO,EAAE,4DAA4D;QACrE,UAAU,EAAE;YACV,iEAAiE;YACjE,oDAAoD;YACpD,gDAAgD;SACjD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yEA6B2D;KACtE;IACD;QACE,WAAW,EAAE,iCAAiC;QAC9C,OAAO,EAAE,6CAA6C;QACtD,UAAU,EAAE;YACV,kDAAkD;YAClD,wDAAwD;YACxD,oDAAoD;YACpD,oDAAoD;SACrD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wEAuE0D;KACrE;IACD;QACE,WAAW,EAAE,wCAAwC;QACrD,OAAO,EAAE,8CAA8C;QACvD,UAAU,EAAE;YACV,mDAAmD;YACnD,wDAAwD;YACxD,oDAAoD;SACrD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iEA+EmD;KAC9D;IACD;QACE,WAAW,EAAE,yCAAyC;QACtD,OAAO,EAAE,+CAA+C;QACxD,UAAU,EAAE;YACV,oDAAoD;YACpD,oDAAoD;SACrD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8EAwEgE;KAC3E;IACD;QACE,WAAW,EAAE,oDAAoD;QACjE,OAAO,EAAE,0DAA0D;QACnE,UAAU,EAAE;YACV,+DAA+D;YAC/D,wDAAwD;SACzD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yDAqG2C;KACtD;IACD;QACE,WAAW,EAAE,6CAA6C;QAC1D,OAAO,EAAE,mDAAmD;QAC5D,UAAU,EAAE,CAAC,wDAAwD,CAAC;QACtE,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qEAqEuD;KAClE;IACD;QACE,WAAW,EAAE,uCAAuC;QACpD,OAAO,EAAE,6CAA6C;QACtD,UAAU,EAAE;YACV,kDAAkD;YAClD,4CAA4C;SAC7C;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aA6ID;KACV;IACD;QACE,WAAW,EAAE,sCAAsC;QACnD,OAAO,EAAE,4CAA4C;QACrD,UAAU,EAAE;YACV,iDAAiD;YACjD,4CAA4C;SAC7C;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+EA+NiE;KAC5E;IACD;QACE,WAAW,EAAE,iDAAiD;QAC9D,OAAO,EAAE,uDAAuD;QAChE,UAAU,EAAE;YACV,4DAA4D;YAC5D,4CAA4C;SAC7C;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uEAuJyD;KACpE;IACD;QACE,WAAW,EAAE,yCAAyC;QACtD,OAAO,EAAE,+CAA+C;QACxD,UAAU,EAAE;YACV,oDAAoD;YACpD,4CAA4C;SAC7C;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qDAyJuC;KAClD;IACD;QACE,WAAW,EAAE,iCAAiC;QAC9C,OAAO,EAAE,uCAAuC;QAChD,UAAU,EAAE;YACV,4CAA4C;YAC5C,sCAAsC;SACvC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uEAgFyD;KACpE;IACD;QACE,WAAW,EAAE,kDAAkD;QAC/D,OAAO,EAAE,wDAAwD;QACjE,UAAU,EAAE;YACV,6DAA6D;YAC7D,sCAAsC;SACvC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mEA2HqD;KAChE;IACD;QACE,WAAW,EAAE,2CAA2C;QACxD,OAAO,EAAE,iDAAiD;QAC1D,UAAU,EAAE;YACV,sDAAsD;YACtD,sCAAsC;SACvC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6CAwI+B;KAC1C;IACD;QACE,WAAW,EAAE,8CAA8C;QAC3D,OAAO,EAAE,oDAAoD;QAC7D,UAAU,EAAE;YACV,yDAAyD;YACzD,sCAAsC;SACvC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uCAuFyB;KACpC;IACD;QACE,WAAW,EAAE,uCAAuC;QACpD,OAAO,EAAE,6CAA6C;QACtD,UAAU,EAAE;YACV,kDAAkD;YAClD,oDAAoD;YACpD,2CAA2C;SAC5C;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8DAiKgD;KAC3D;IACD;QACE,WAAW,EAAE,8CAA8C;QAC3D,OAAO,EAAE,oDAAoD;QAC7D,UAAU,EAAE;YACV,yDAAyD;YACzD,2CAA2C;SAC5C;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uCAsIyB;KACpC;IACD;QACE,WAAW,EAAE,yDAAyD;QACtE,OAAO,EAAE,+DAA+D;QACxE,UAAU,EAAE;YACV,oEAAoE;YACpE,2CAA2C;SAC5C;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2EA0I6D;KACxE;IACD;QACE,WAAW,EAAE,iDAAiD;QAC9D,OAAO,EAAE,uDAAuD;QAChE,UAAU,EAAE;YACV,4DAA4D;YAC5D,2CAA2C;SAC5C;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iCA8HmB;KAC9B;IACD;QACE,WAAW,EAAE,wBAAwB;QACrC,OAAO,EAAE,kDAAkD;QAC3D,UAAU,EAAE;YACV,uDAAuD;SACxD;QACL,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iCAgFuB;KAC9B;IACD;QACE,WAAW,EAAE,8CAA8C;QAC3D,OAAO,EAAE,oDAAoD;QAC7D,UAAU,EAAE;YACV,yDAAyD;YACzD,6DAA6D;SAC9D;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yCAwD2B;KACtC;IACD;QACE,WAAW,EAAE,gDAAgD;QAC7D,OAAO,EAAE,sDAAsD;QAC/D,UAAU,EAAE;YACV,2DAA2D;SAC5D;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mDA4HqC;KAChD;IACD;QACE,WAAW,EAAE,8CAA8C;QAC3D,OAAO,EAAE,iDAAiD;QAC1D,UAAU,EAAE;YACV,sDAAsD;YACtD,wDAAwD;YACxD,gDAAgD;YAChD,6DAA6D;SAC9D;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4CAwH8B;KACzC;IACD;QACE,WAAW,EAAE,2CAA2C;QACxD,OAAO,EAAE,iDAAiD;QAC1D,UAAU,EAAE;YACV,sDAAsD;SACvD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kCAuJoB;KAC/B;IACD;QACE,WAAW,EAAE,kDAAkD;QAC/D,OAAO,EAAE,wDAAwD;QACjE,UAAU,EAAE;YACV,6DAA6D;YAC7D,wDAAwD;YACxD,+DAA+D;YAC/D,yCAAyC;SAC1C;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yBAiEW;KACtB;IACD;QACE,WAAW,EAAE,2DAA2D;QACxE,OAAO,EAAE,iEAAiE;QAC1E,UAAU,EAAE,CAAC,sEAAsE,CAAC;QACpF,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+DA2EiD;KAC5D;IACD;QACE,WAAW,EAAE,wDAAwD;QACrE,OAAO,EAAE,8DAA8D;QACvE,UAAU,EAAE;YACV,mEAAmE;YACnE,+DAA+D;SAChE;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6CAwE+B;KAC1C;IACD;QACE,WAAW,EAAE,mDAAmD;QAChE,OAAO,EAAE,yDAAyD;QAClE,UAAU,EAAE,CAAC,8DAA8D,CAAC;QAC5E,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mDAuDqC;KAChD;IACD;QACE,WAAW,EAAE,+CAA+C;QAC5D,OAAO,EAAE,qDAAqD;QAC9D,UAAU,EAAE;YACV,0DAA0D;SAC3D;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2DAkH6C;KACxD;IACD;QACE,WAAW,EAAE,gDAAgD;QAC7D,OAAO,EAAE,sDAAsD;QAC/D,UAAU,EAAE;YACV,2DAA2D;SAC5D;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4CA2F8B;KACzC;IACD;QACE,WAAW,EAAE,iDAAiD;QAC9D,OAAO,EAAE,uDAAuD;QAChE,UAAU,EAAE,CAAC,4DAA4D,CAAC;QAC1E,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2CA4E6B;KACxC;IACD;QACE,WAAW,EAAE,0CAA0C;QACvD,OAAO,EAAE,mCAAmC;QAC5C,UAAU,EAAE;YACV,wCAAwC;YACxC,qDAAqD;SACtD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oCAoFsB;KACjC;IACD;QACE,WAAW,EAAE,mDAAmD;QAChE,OAAO,EAAE,yDAAyD;QAClE,UAAU,EAAE;YACV,8DAA8D;YAC9D,oDAAoD;YACpD,qDAAqD;SACtD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wEA4K0D;KACrE;IACD;QACE,WAAW,EAAE,uCAAuC;QACpD,OAAO,EAAE,6CAA6C;QACtD,UAAU,EAAE;YACV,kDAAkD;YAClD,oDAAoD;YACpD,qDAAqD;SACtD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAuGJ;KACP;IACD;QACE,WAAW,EAAE,6CAA6C;QAC1D,OAAO,EAAE,mDAAmD;QAC5D,UAAU,EAAE,CAAC,wDAAwD,CAAC;QACtE,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iFAuHmE;KAC9E;IACD;QACE,WAAW,EAAE,kCAAkC;QAC/C,OAAO,EAAE,wCAAwC;QACjD,UAAU,EAAE,CAAC,6CAA6C,CAAC;QAC3D,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wEAqG0D;KACrE;IACD;QACE,WAAW,EAAE,uDAAuD;QACpE,OAAO,EAAE,6DAA6D;QACtE,UAAU,EAAE,CAAC,kEAAkE,CAAC;QAChF,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mDAsHqC;KAChD;IACD;QACE,WAAW,EAAE,mDAAmD;QAChE,OAAO,EAAE,yDAAyD;QAClE,UAAU,EAAE,CAAC,8DAA8D,CAAC;QAC5E,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA2EU;KACrB;IACD;QACE,WAAW,EAAE,mDAAmD;QAChE,OAAO,EAAE,yDAAyD;QAClE,UAAU,EAAE,CAAC,8DAA8D,CAAC;QAC5E,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mDAuDqC;KAChD;IACD;QACE,WAAW,EAAE,sDAAsD;QACnE,OAAO,EAAE,4DAA4D;QACrE,UAAU,EAAE,CAAC,iEAAiE,CAAC;QAC/E,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA0DO;KAClB;IACD;QACE,WAAW,EAAE,4CAA4C;QACzD,OAAO,EAAE,6CAA6C;QACtD,UAAU,EAAE,CAAC,kDAAkD,CAAC;QAChE,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4DAkF8C;KACzD;IACD;QACE,WAAW,EAAE,yCAAyC;QACtD,OAAO,EAAE,sDAAsD;QAC/D,UAAU,EAAE;YACV,2DAA2D;YAC3D,+CAA+C;SAChD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6CAyG+B;KAC1C;IACD;QACE,WAAW,EAAE,6CAA6C;QAC1D,OAAO,EAAE,mEAAmE;QAC5E,UAAU,EAAE,CAAC,wEAAwE,CAAC;QACtF,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mEA8EqD;KAChE;IACD;QACE,WAAW,EAAE,4CAA4C;QACzD,OAAO,EAAE,mDAAmD;QAC5D,UAAU,EAAE,CAAC,wDAAwD,CAAC;QACtE,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gJAqGkI;KAC7I;IACD;QACE,WAAW,EAAE,sCAAsC;QACnD,OAAO,EAAE,oDAAoD;QAC7D,UAAU,EAAE;YACV,yDAAyD;YACzD,+CAA+C;SAChD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+BA0LiB;KAC5B;IACD;QACE,WAAW,EAAE,mCAAmC;QAChD,OAAO,EAAE,0CAA0C;QACnD,UAAU,EAAE;YACV,+CAA+C;YAC/C,+CAA+C;SAChD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oEAgHsD;KACjE;IACD;QACE,WAAW,EAAE,+CAA+C;QAC5D,OAAO,EAAE,sDAAsD;QAC/D,UAAU,EAAE;YACV,2DAA2D;YAC3D,+CAA+C;SAChD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wCA+F0B;KACrC;IACD;QACE,WAAW,EAAE,oCAAoC;QACjD,OAAO,EAAE,2CAA2C;QACpD,UAAU,EAAE;YACV,gDAAgD;YAChD,+CAA+C;SAChD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yDAsH2C;KACtD;IACD;QACE,WAAW,EAAE,oCAAoC;QACjD,OAAO,EAAE,qEAAqE;QAC9E,UAAU,EAAE;YACV,0EAA0E;YAC1E,+CAA+C;SAChD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wEA0F0D;KACrE;IACD;QACE,WAAW,EAAE,oDAAoD;QACjE,OAAO,EAAE,2DAA2D;QACpE,UAAU,EAAE,CAAC,gEAAgE,CAAC;QAC9E,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA6EU;KACrB;IACD;QACE,WAAW,EAAE,wCAAwC;QACrD,OAAO,EAAE,gEAAgE;QACzE,UAAU,EAAE,CAAC,qEAAqE,CAAC;QACnF,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4EA4F8D;KACzE;IACD;QACE,WAAW,EAAE,iBAAiB;QAC9B,OAAO,EAAE,2CAA2C;QACpD,UAAU,EAAE,CAAC,gDAAgD,CAAC;QAC9D,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yNA8E2M;KACtN;IACD;QACE,WAAW,EAAE,sCAAsC;QACnD,OAAO,EAAE,mDAAmD;QAC5D,UAAU,EAAE,CAAC,wDAAwD,CAAC;QACtE,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uDAoDyC;KACpD;IACD;QACE,WAAW,EAAE,gCAAgC;QAC7C,OAAO,EAAE,0CAA0C;QACnD,UAAU,EAAE;YACV,+CAA+C;YAC/C,oDAAoD;YACpD,sCAAsC;SACvC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8CAgLgC;KAC3C;IACD;QACE,WAAW,EAAE,mCAAmC;QAChD,OAAO,EAAE,6CAA6C;QACtD,UAAU,EAAE;YACV,kDAAkD;YAClD,oDAAoD;YACpD,sCAAsC;SACvC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mDA+JqC;KAChD;IACD;QACE,WAAW,EAAE,iCAAiC;QAC9C,OAAO,EAAE,2CAA2C;QACpD,UAAU,EAAE;YACV,gDAAgD;YAChD,oDAAoD;YACpD,sCAAsC;SACvC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uDA4JyC;KACpD;IACD;QACE,WAAW,EAAE,iCAAiC;QAC9C,OAAO,EAAE,8CAA8C;QACvD,UAAU,EAAE;YACV,mDAAmD;YACnD,oDAAoD;SACrD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBAuDS;KACpB;IACD;QACE,WAAW,EAAE,iCAAiC;QAC9C,OAAO,EAAE,6CAA6C;QACtD,UAAU,EAAE;YACV,kDAAkD;YAClD,oDAAoD;SACrD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sCAoIwB;KACnC;IACD;QACE,WAAW,EAAE,gCAAgC;QAC7C,OAAO,EAAE,4CAA4C;QACrD,UAAU,EAAE;YACV,iDAAiD;YACjD,oDAAoD;SACrD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4DAkI8C;KACzD;IACD;QACE,WAAW,EAAE,sCAAsC;QACnD,OAAO,EAAE,kDAAkD;QAC3D,UAAU,EAAE;YACV,uDAAuD;YACvD,oDAAoD;SACrD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAyHJ;KACP;IACD;QACE,WAAW,EAAE,wBAAwB;QACrC,OAAO,EAAE,qDAAqD;QAC9D,UAAU,EAAE,CAAC,0DAA0D,CAAC;QACxE,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gEAuHkD;KAC7D;IACD;QACE,WAAW,EAAE,6CAA6C;QAC1D,OAAO,EAAE,4CAA4C;QACrD,UAAU,EAAE;YACV,iDAAiD;YACjD,oDAAoD;YACpD,sCAAsC;SACvC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8DAgLgD;KAC3D;IACD;QACE,WAAW,EAAE,0BAA0B;QACvC,OAAO,EAAE,8CAA8C;QACvD,UAAU,EAAE;YACV,mDAAmD;SACpD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;2KA0B6J;KACxK;IACD;QACE,WAAW,EAAE,kCAAkC;QAC/C,OAAO,EAAE,mDAAmD;QAC5D,UAAU,EAAE;YACV,wDAAwD;YACxD,oDAAoD;YACpD,sCAAsC;YACtC,uCAAuC;SACxC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wUAyF0T;KACrU;IACD;QACE,WAAW,EAAE,mCAAmC;QAChD,OAAO,EAAE,+CAA+C;QACxD,UAAU,EAAE;YACV,oDAAoD;YACpD,oDAAoD;YACpD,sCAAsC;SACvC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0VA0E4U;KACvV;IACD;QACE,WAAW,EAAE,uCAAuC;QACpD,OAAO,EAAE,wDAAwD;QACjE,UAAU,EAAE;YACV,6DAA6D;YAC7D,uCAAuC;SACxC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mSAmEqR;KAChS;IACD;QACE,WAAW,EAAE,0CAA0C;QACvD,OAAO,EAAE,8DAA8D;QACvE,UAAU,EAAE;YACV,mEAAmE;YACnE,uCAAuC;SACxC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2WAyD6V;KACxW;IACD;QACE,WAAW,EAAE,mCAAmC;QAChD,OAAO,EAAE,uDAAuD;QAChE,UAAU,EAAE;YACV,4DAA4D;YAC5D,sCAAsC;YACtC,uCAAuC;SACxC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iOA4DmN;KAC9N;IACD;QACE,WAAW,EAAE,0BAA0B;QACvC,OAAO,EAAE,uCAAuC;QAChD,UAAU,EAAE;YACV,4CAA4C;YAC5C,qDAAqD;YACrD,wCAAwC;SACzC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yIAmC2H;KACtI;IACD;QACE,WAAW,EAAE,6CAA6C;QAC1D,OAAO,EAAE,kEAAkE;QAC3E,UAAU,EAAE;YACV,uEAAuE;YACvE,wCAAwC;SACzC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0TA+C4S;KACvT;IACD;QACE,WAAW,EAAE,0CAA0C;QACvD,OAAO,EAAE,sDAAsD;QAC/D,UAAU,EAAE;YACV,2DAA2D;YAC3D,wCAAwC;SACzC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;idAsDmc;KAC9c;IACD;QACE,WAAW,EAAE,6CAA6C;QAC1D,OAAO,EAAE,yDAAyD;QAClE,UAAU,EAAE;YACV,8DAA8D;YAC9D,wCAAwC;SACzC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iUAqDmT;KAC9T;IACD;QACE,WAAW,EAAE,uCAAuC;QACpD,OAAO,EAAE,8DAA8D;QACvE,UAAU,EAAE;YACV,mEAAmE;YACnE,wCAAwC;SACzC;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4PAyC8O;KACzP;IACD;QACE,WAAW,EAAE,qBAAqB;QAClC,OAAO,EAAE,+CAA+C;QACxD,UAAU,EAAE;YACV,oDAAoD;YACpD,oDAAoD;YACpD,qDAAqD;SACtD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAkQa;KACxB;IACD;QACE,WAAW,EAAE,qBAAqB;QAClC,OAAO,EAAE,+CAA+C;QACxD,UAAU,EAAE;YACV,oDAAoD;YACpD,oDAAoD;SACrD;QACD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+DAgTiD;KAC5D;CACO,CAAC","sourcesContent":["/**\n * Canonical engine-owned application-consumer documentation fragments.\n *\n * This neutral reusable-content module is deliberately data-only: no imports,\n * calls, environment reads, Wildo application-authoring guidance or executable\n * MDX. Companion-side projectors validate and digest these values before any\n * generated application may consume them.\n *\n * The fragments describe customer-facing product domains and integration\n * journeys, not a generic “technical guides” catalogue.\n *\n * This header used to say application-domain use cases were \"deliberately absent until the\n * app-creator flow owns their authoring and acceptance\". That sentence is retired, and it is worth\n * keeping the reason: stated as policy, the largest gap in the whole site read as a decision\n * rather than a defect, and survived every review for exactly that long. A customer could learn\n * how to verify a webhook signature before learning what the product manages.\n *\n * `what-this-application-manages.md` closes it WITHOUT anyone authoring per-application prose,\n * which is what the original reservation was protecting: the page is engine-authored and every\n * fact in it is projected from sources the application already accepted — its own resource\n * registry, its declared API-reference categories, and each specification's purpose and lifecycle.\n *\n * What remains genuinely deferred is a page PER resource. Those need a variable unit set, and the\n * renderer's route table is deliberately fixed (see `pathForUnit`), so an application-owned unit\n * still fails closed rather than acquiring an implicit route.\n */\nexport const APPLICATION_CONSUMER_DOCUMENTATION_AUTHORED_CONTENT_V1 = [\n {\n managedPath: 'get-started.md',\n unitRef: 'technical-documentation:unit/application-orientation',\n sourceRefs: [\n 'saas-technical-doc:engine-content/application-orientation',\n 'source:companion-projection:application-connection',\n ],\n 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| Understand what this application is for | [What {{APPLICATION_NAME}} manages](/what-this-application-manages) | The things it manages, in its own words, and who may act on each |\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| 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.`,\n },\n {\n managedPath: 'what-this-application-manages.md',\n unitRef: 'technical-documentation:unit/what-this-application-manages',\n sourceRefs: [\n 'saas-technical-doc:engine-content/what-this-application-manages',\n 'source:companion-projection:application-connection',\n 'source:companion-projection:application-domain',\n ],\n markdown: `# What {{APPLICATION_NAME}} manages\n\nEvery other page here explains how to reach this application, administer it, integrate with it or\npay for it. This one says what it is FOR.\n\nEverything below is the application's own: the things it stores, the words it uses for them, and\nwho may act on each. None of it is written by the framework — it is read from the application's own\nresource definitions, so it says what this deployment actually publishes rather than what a product\nof this kind usually does.\n\n## What it manages\n\n{{APPLICATION_DOMAIN:domainOverview}}\n\n## Each one in detail\n\n{{APPLICATION_DOMAIN:domainResourceDetails}}\n\n## Where to go next\n\n| You need to | Go to |\n| --- | --- |\n| Read or change any of this from your own code | [Send your first API request](/integrations/rest/send-request) |\n| Look up the exact fields, arguments and responses | [API reference](/api) |\n| Be notified when one of these changes | [Webhooks](/integrations/webhooks) |\n| Let an AI assistant work with them | [AI coding tools](/integrations/ai-coding-tools) |\n| Change who may act on them | [Roles in this application](/user-administration/roles-and-permissions) |\n\nThe names above are the API's own, so a name you read here is the one you will send, the one an\nerror message will quote back, and the one a webhook payload will carry.`,\n },\n {\n managedPath: 'access-and-identity/overview.md',\n unitRef: 'technical-documentation:unit/authentication',\n sourceRefs: [\n 'saas-technical-doc:engine-content/authentication',\n 'source:companion-projection:application-authentication',\n 'source:companion-projection:application-connection',\n 'source:consumer-fact:access-authentication-methods',\n ],\n 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.`,\n },\n {\n managedPath: 'access-and-identity/sign-in-and-mfa.md',\n unitRef: 'technical-documentation:unit/sign-in-and-mfa',\n sourceRefs: [\n 'saas-technical-doc:engine-content/sign-in-and-mfa',\n 'source:companion-projection:application-authentication',\n 'source:consumer-fact:access-authentication-methods',\n ],\n 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.`,\n },\n {\n managedPath: 'access-and-identity/complete-sign-in.md',\n unitRef: 'technical-documentation:unit/complete-sign-in',\n sourceRefs: [\n 'saas-technical-doc:engine-content/complete-sign-in',\n 'source:consumer-fact:access-authentication-methods',\n ],\n 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.`,\n },\n {\n managedPath: 'access-and-identity/mfa-enrollment-and-recovery.md',\n unitRef: 'technical-documentation:unit/mfa-enrollment-and-recovery',\n sourceRefs: [\n 'saas-technical-doc:engine-content/mfa-enrollment-and-recovery',\n 'source:companion-projection:application-authentication',\n ],\n 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.`,\n },\n {\n managedPath: 'access-and-identity/sign-in-troubleshoot.md',\n unitRef: 'technical-documentation:unit/sign-in-troubleshoot',\n sourceRefs: ['saas-technical-doc:engine-content/sign-in-troubleshoot'],\n 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.`,\n },\n {\n managedPath: 'access-and-identity/single-sign-on.md',\n unitRef: 'technical-documentation:unit/single-sign-on',\n sourceRefs: [\n 'saas-technical-doc:engine-content/single-sign-on',\n 'source:consumer-fact:access-single-sign-on',\n ],\n markdown: `# Single sign-on\n\nSingle sign-on lets people authenticate through an organization's identity\nprovider. It changes **how identity is proven**; it does not create membership,\nchoose roles or remove access when somebody leaves. Use [User\nadministration](/user-administration) or SCIM for those lifecycle decisions.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Identify the organization, identity-provider owner, application owner and an independent administrator recovery method | People enter through the intended provider, resolve to the intended organization and receive only their approved application access |\n\n## Know what SSO owns\n\n| Question | Owned by SSO? | Where to manage it |\n| --- | --- | --- |\n| How does the person prove identity? | **Yes** | Identity-provider policy and this connection's trust settings |\n| May a new provider identity create an application user? | **Connection-dependent** | Just-in-time creation and identity-mapping controls |\n| Is the person a member of this organization? | **No** | Manual user administration or SCIM lifecycle policy |\n| Which application operations may the person perform? | **No** | Organization roles and the exact operation contract |\n| Does leaving the identity provider remove application access? | **Not by SSO alone** | Manual suspension/removal or SCIM deprovisioning |\n\nThis separation matters during both setup and incidents. A provider can accept a\nperson while the application correctly refuses an inactive membership, and an\nactive application membership can remain after provider access is removed if no\nuser-lifecycle process updates it.\n\n~~~mermaid\nsequenceDiagram\n accTitle: Sign in through an organization identity provider\n accDescr: A person starts at the application, authenticates through the configured identity provider, and returns with a response the application validates before starting a session.\n participant Person\n participant App as Application\n participant IdP as Identity provider\n Person->>App: Start organization sign-in\n App->>IdP: Redirect using configured connection\n IdP->>Person: Authenticate and satisfy provider policy\n IdP->>App: Return signed response\n App->>App: Validate trust and organization context\n App-->>Person: Start application session\n~~~\n\nThe result is not merely a completed redirect. The response must come from the\nintended provider, validate for this environment and map to the intended person\nand organization.\n\n## Choose a connection protocol with the provider owner\n\nThe application supports the connection protocols shown below. Use the protocol\nthe organization's provider can operate and monitor consistently; do not choose\none because its configuration form looks shorter.\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#markdown}}\n\n- **OpenID Connect** commonly uses provider discovery, an issuer, a client\n identity, a protected client secret and signed tokens. The application must\n validate the response for the exact issuer, audience and environment.\n- **SAML** commonly uses provider and application entity identifiers, sign-in\n destinations and signing certificates. The application must validate the\n signature, audience, destination and timing of the assertion.\n\nBoth protocols still require a stable person mapping, an organization\nmembership decision and an access test after authentication.\n\n~~~mermaid\nflowchart TD\n accTitle: Choose the protocol the organization can operate safely\n accDescr: The organization first checks which protocols the application and provider support, then prefers OpenID Connect for a new compatible integration, retains SAML for an established enterprise federation, and verifies the same identity, membership and recovery outcomes in either case.\n start[\"Application and provider owners meet\"] --> supported{\"Both sides support OIDC?\"}\n supported -->|\"Yes\"| oidc[\"Prefer OIDC for a new connection\"]\n supported -->|\"No\"| samlSupported{\"Both sides support SAML 2.0?\"}\n samlSupported -->|\"Yes\"| saml[\"Configure SAML federation\"]\n samlSupported -->|\"No\"| stop[\"No supported SSO connection\"]\n oidc --> proof[\"Prove identity, organization, role and recovery\"]\n saml --> proof\n~~~\n\nThe choice is operational, not cosmetic. OIDC exchanges compact signed tokens\nand normally publishes provider metadata. SAML exchanges signed XML assertions\nand commonly uses federation metadata plus signing certificates. **Do not\ntranslate values between the protocols by name alone**: an OIDC issuer is not a\nSAML entity ID, an OIDC redirect URI is not a SAML audience, and a signing-key\nset is not interchangeable with a SAML certificate configuration.\n\n| Decision | Prefer OpenID Connect when… | Prefer SAML when… |\n| --- | --- | --- |\n| Existing provider integration | The provider operates a maintained OIDC application registration | The organization already operates a reviewed SAML enterprise application |\n| Trust renewal | Issuer metadata and signing keys can be monitored through the provider | Certificate lifecycle and federation metadata already have named owners |\n| Identity data | Stable OIDC claims can provide the required person attributes | Existing SAML attribute statements already carry the required attributes |\n| Provider-started access | Application-started authorization is acceptable | A deliberately approved IdP-started journey is required and tested |\n| New implementation | Both sides support authorization code with PKCE and strict issuer/audience validation | OIDC is unavailable or the provider's supported enterprise contract is SAML |\n\n## Understand the standards before changing trust\n\n- [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html)\n defines the identity layer, authorization response and ID-token validation.\n- [OpenID Connect Discovery 1.0](https://openid.net/specs/openid-connect-discovery-1_0.html)\n defines provider metadata such as issuer, endpoints and signing-key location.\n- [OAuth 2.0 authorization-server metadata (RFC 8414)](https://www.rfc-editor.org/rfc/rfc8414)\n describes discovery metadata used by OAuth/OIDC deployments.\n- [Proof Key for Code Exchange (RFC 7636)](https://www.rfc-editor.org/rfc/rfc7636)\n defines the code-verifier protection used by the default OIDC journey.\n- [OASIS SAML 2.0 technical overview](https://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-tech-overview-2.0.html)\n explains SAML roles, assertions and the browser SSO profiles.\n- [OASIS SAML 2.0 metadata](https://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf)\n defines the metadata exchanged between federation parties.\n\nThese documents define the protocol. The current application's displayed\nconnection values remain the authority for its URLs, identifiers and enabled\nfeatures.\n\n## Start with your provider's maintained instructions\n\n| Provider | OIDC starting point | SAML starting point |\n| --- | --- | --- |\n| Microsoft Entra ID | [Configure OIDC SSO for gallery and custom applications](https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/add-application-portal-setup-oidc-sso) | [Enable SAML SSO for an enterprise application](https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/add-application-portal-setup-sso) |\n| Okta | [Create an OIDC app integration](https://help.okta.com/en-us/content/topics/apps/apps_app_integration_wizard_oidc.htm) | [Create a SAML app integration](https://help.okta.com/en-us/content/topics/apps/apps_app_integration_wizard_saml.htm) |\n| Google Workspace or Cloud Identity | [Google OpenID Connect reference](https://developers.google.com/identity/openid-connect/openid-connect) | [Set up a custom SAML application](https://support.google.com/a/answer/6087519) |\n\nProvider documentation explains the provider side. Continue with the\napplication configuration guide to map those provider values to this\nenvironment's exact connection fields.\n\n## Follow the SSO journey\n\n| Your next task | Start here | Successful result |\n| --- | --- | --- |\n| Establish a new trust connection | [Configure a single sign-on connection](/access-and-identity/sso-configure) | The application and provider agree on protocol, identity, destinations and verification settings |\n| Introduce SSO safely | [Roll out SSO and keep a recovery path](/access-and-identity/sso-rollout-and-recovery) | A pilot signs in correctly and administrators retain an independent recovery method |\n| Investigate a failure | [Troubleshoot single sign-on](/access-and-identity/sso-troubleshoot) | The failing provider, trust, mapping, membership or role decision is identified without weakening validation |\n\nAn enabled connection can be used; a default connection may be selected\nautomatically by the sign-in experience. Do not make a connection default until\nits complete return journey and organization mapping have been verified.\n\n## Operate SSO as a shared service\n\nRecord owners for the provider and application configuration, the independent\nrecovery method, last controlled test, certificate or client-secret renewal\ndate, and the manual/SCIM process that removes organization access. Review trust\nand mapping changes as security changes. Keep passwords, client secrets, private\nkeys, complete assertions and session cookies out of ordinary tickets and\nscreenshots.`,\n },\n {\n managedPath: 'access-and-identity/sso-configure.md',\n unitRef: 'technical-documentation:unit/sso-configure',\n sourceRefs: [\n 'saas-technical-doc:engine-content/sso-configure',\n 'source:consumer-fact:access-single-sign-on',\n ],\n markdown: `# Configure a single sign-on connection\n\nCreate one connection for one organization and environment. This task is for an\norganization administrator working with the identity administrator who controls\nthe provider tenant.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Have an independent administrator recovery method, provider administration access, the current application's connection values and a controlled test identity | The application and provider identify each other correctly and a test response validates for the intended organization |\n\n~~~mermaid\nflowchart TD\n accTitle: Configure one single sign-on trust boundary\n accDescr: The application and identity-provider owners choose one protocol, exchange environment-specific identities and destinations, configure validation and identity mapping, test while the connection is not default, and enable it only after identity, organization and access checks pass.\n owners[\"Confirm owners and independent recovery\"] --> protocol[\"Choose OpenID Connect or SAML\"]\n protocol --> trust[\"Exchange identities, destinations and verification material\"]\n trust --> mapping[\"Define person, domain and role mapping\"]\n mapping --> controlled[\"Test one controlled identity\"]\n controlled --> access[\"Verify identity, organization, allowed action and refusal\"]\n access --> enable[\"Enable without making default\"]\n~~~\n\nKeep the connection isolated to one organization and environment. Production\nand non-production values may have similar labels but remain different trust\nboundaries.\n\n## Choose the protocol and connection controls\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#markdown}}\n\nGive the connection a display name that identifies the organization and\nenvironment. Keep it disabled while exchanging trust configuration when the\nadministration surface permits that sequence. Do not mark it as default yet.\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#connectionConfigurationMarkdown}}\n\n> **Current limitation:** keep \\`bypassAppMFA\\` off. The configuration field is\n> present, but the current authentication runtime does not use it to decide\n> whether the application requests another factor. Prove the actual sign-in\n> journey with a controlled account; do not use this field as audit evidence.\n\n> **SSO role mapping is an access grant.** Test every mapped value, keep the\n> fallback role non-administrative, and verify an expected refusal. A provider\n> group name should never become broad application authority merely because it\n> was previously used for a different system.\n\n## Exchange the trust configuration\n\nDepending on the selected protocol, the two administrators exchange the\nnon-secret identifiers and destinations needed to identify the application and\nprovider, plus the protected verification or client material required by that\nprotocol. Use only values displayed for the current environment.\n\nCheck these meanings before saving:\n\n- **Provider identity** names the provider tenant this connection trusts.\n- **Application identity or audience** tells the provider which application the\n response is intended for.\n- **Sign-in and return destinations** must belong to the matching environments.\n- **Identity mapping** must use a stable identity value rather than a display\n name that can change or collide.\n- **Verification settings** decide which signed responses the application will\n trust and how timing is evaluated.\n\n~~~mermaid\nflowchart LR\n accTitle: Map provider values to one application connection\n accDescr: The application publishes its callback or assertion-consumer destination and identity. The provider publishes its issuer or entity identity, endpoints and verification material. Both owners configure stable identity claims, and the application alone maps those claims to membership and least-privilege roles.\n app[\"Application environment\"] -->|\"Callback or ACS destination; application identity\"| provider[\"Identity provider tenant\"]\n provider -->|\"Issuer or entity ID; endpoints; signing material\"| app\n provider --> claims[\"Stable identity and optional role/group claims\"]\n claims --> mapping[\"Application claim and access mapping\"]\n mapping --> membership[\"Person + organization membership + roles\"]\n~~~\n\nThe arrows show two separate exchanges. Protocol trust lets the application\naccept a response from the provider. Claim and access mapping decides which\nperson and organization relationship that response may establish. Review both;\na valid signature does not make an unsafe group-to-admin mapping acceptable.\n\n### For an OpenID Connect connection\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#oidcConfigurationMarkdown}}\n\nPrefer the provider's maintained discovery information when the administration\nsurface supports it. Confirm the issuer and discovered authorization, token and\nsigning-key locations all belong to the same provider environment. Register the\nexact application return destination at the provider. Protect the client secret\nas write-only credential material, retain its renewal owner, and keep issuer and\naudience validation enabled. Use the strong proof method offered for the\nauthorization-code journey rather than weakening it to accommodate an old\nclient.\n\nChoose one endpoint mode deliberately:\n\n1. **Discovery** — supply the provider issuer or discovery URL. The sign-in\n runtime retrieves the current metadata and uses its issuer, authorization,\n token, user-info, signing-key and logout locations when published.\n2. **Provider template** — choose a maintained provider contract and supply its\n required tenant substitutions. Verify every resolved URL before enabling.\n3. **Manual** — supply the authorization and token endpoints, plus issuer,\n user-info and signing-key locations where required. Use this only when the\n provider cannot publish usable metadata.\n\n> The administrative **Discover endpoints** and **Test connection** operations\n> currently return \\`supported: false\\` for OIDC and perform no provider\n> handshake. This does not disable discovery-mode sign-in; it means the admin\n> diagnostic action cannot prove that connection. Use a controlled end-to-end\n> sign-in and provider logs as the positive test.\n\n### For a SAML connection\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#samlConfigurationMarkdown}}\n\nConfirm the provider entity identifier, application audience, sign-in\ndestination and assertion return destination as a single environment-specific\nset. Load the current provider signing certificate through the protected\nadministration surface and plan renewal before it expires. Keep signed-assertion\nvalidation enabled. Choose a stable subject/NameID and explicit attribute\nmapping; do not use a mutable display name as the person's identity.\n\nThe administrative **Discover endpoints** operation can retrieve SAML metadata\nand return the provider entity ID, sign-in/logout URLs, certificates and NameID\nformat for review. It does **not** save those values. After saving the\nconnection, **Test connection** checks the configured entity ID, endpoint\nreachability, certificate validity and generated service-provider metadata. A\npass is useful preflight evidence, but only a real application-started sign-in\nproves the browser, provider policy, response validation and identity mapping.\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#diagnosticsMarkdown}}\n\n## Configure a common identity provider\n\nThe provider changes the names and screens, not the application trust model.\nAlways copy the application values from the **same environment** you are\nconfiguring; the examples below deliberately contain no reusable callback URL,\nentity ID, client ID or secret.\n\n| Application meaning | Microsoft Entra ID | Okta | Google Workspace / Cloud Identity |\n| --- | --- | --- | --- |\n| OIDC application identity | App registration **Application (client) ID** | OIDC app **Client ID** | OAuth client **Client ID** |\n| OIDC return destination | App registration **Redirect URI** | **Sign-in redirect URI** | OAuth client **Authorized redirect URI** |\n| OIDC provider identity | Tenant-specific issuer/discovery document | Okta authorization-server issuer | Google issuer/discovery document |\n| SAML application identity | **Identifier (Entity ID)** | **Audience URI (SP Entity ID)** | **Entity ID** |\n| SAML return destination | **Reply URL (ACS URL)** | **Single sign-on URL** | **ACS URL** |\n| SAML provider identity | Microsoft Entra Identifier | Identity Provider Issuer | Google Entity ID |\n| SAML verification material | SAML signing certificate / federation metadata | Signing certificate / IdP metadata | Certificate / IdP metadata |\n\n### Microsoft Entra ID\n\nFor OIDC, create or select the application registration, register the exact web\nredirect URI supplied by this application environment, use the tenant-specific\nissuer, and create a client credential with a named owner and expiry. Keep the\nprovider assignment limited to the pilot population. Microsoft distinguishes\nthe app registration (the application definition) from its enterprise\napplication/service-principal instance; record both identities during support.\n\nFor SAML, create or select the enterprise application, configure its Identifier\nand Reply URL from this environment, then load the Microsoft Entra Identifier,\nlogin URL and current signing certificate into the SAML connection. Review the\nprovider's claims before authoring role or group mappings.\n\n- [Microsoft Entra OIDC application setup](https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/add-application-portal-setup-oidc-sso)\n- [Microsoft Entra SAML application setup](https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/add-application-portal-setup-sso)\n- [Microsoft Entra redirect URI rules](https://learn.microsoft.com/en-us/entra/identity-platform/how-to-add-redirect-uri)\n\n### Okta\n\nCreate a private OIDC or SAML app integration and initially assign only the\npilot people or groups. For OIDC, choose a **Web Application**, register the\nexact sign-in redirect URI, retain authorization code, and keep PKCE S256. Copy\nthe client ID, client secret and exact issuer used by that authorization server.\nDo not enable a wildcard redirect merely to avoid maintaining environment URLs.\n\nFor SAML, enter this environment's ACS URL and service-provider entity ID, then\nload Okta's Identity Provider issuer, sign-on URL and signing certificate into\nthe application connection. Map claims and groups explicitly; an Okta\nassignment decides who may reach the provider integration, while the\napplication membership and roles still decide application access.\n\n- [Okta OIDC app integration](https://help.okta.com/en-us/content/topics/apps/apps_app_integration_wizard_oidc.htm)\n- [Okta SAML app integration](https://help.okta.com/en-us/content/topics/apps/apps_app_integration_wizard_saml.htm)\n- [Okta SAML field reference](https://help.okta.com/en-us/content/topics/apps/aiw-saml-reference.htm)\n\n### Google Workspace or Cloud Identity\n\nFor OIDC, configure a web OAuth client with the exact authorized redirect URI\nand use Google's published issuer/discovery information. The provider can\nauthenticate Google accounts beyond one Workspace domain, so the application\nconnection's explicit allowed-domain list and the organization's membership\npolicy remain important boundaries.\n\nFor SAML, add a custom SAML app, copy Google's IdP entity ID, SSO URL and\ncertificate into this connection, then enter the application's ACS URL and\nentity ID in Google. Start with the service disabled or assigned to a pilot\norganizational unit/group, depending on the provider controls available to the\norganization.\n\n- [Google OpenID Connect guide](https://developers.google.com/identity/openid-connect/openid-connect)\n- [Google custom SAML application setup](https://support.google.com/a/answer/6087519)\n\n> **Do not paste credentials, private keys or complete certificates into a\n> ticket or screenshot.** Use the protected administration surfaces to exchange\n> sensitive material and share only non-secret identifiers for diagnosis.\n\n## Verify before enabling broadly\n\nEnable the connection for a controlled test, but do not make it default. Start\nfrom the application's sign-in journey and verify:\n\n1. the intended provider and environment receive the request;\n2. the provider accepts the controlled person under its expected policy;\n3. the application accepts the returned issuer/entity, audience, destination,\n signature and time checks;\n4. the stable subject maps to the intended application person;\n5. the person enters the intended organization with the expected role;\n6. one expected action succeeds and one action outside that authority is\n refused; and\n7. the independent recovery administrator still signs in.\n\nRecord non-secret identifiers, time, outcome and correlation evidence. Continue with\n[Roll out SSO and keep a recovery path](/access-and-identity/sso-rollout-and-recovery)\nbefore making it the default. Never include a password, client secret, private\nkey, complete assertion, authorization code or session cookie in the evidence.`,\n },\n {\n managedPath: 'access-and-identity/sso-rollout-and-recovery.md',\n unitRef: 'technical-documentation:unit/sso-rollout-and-recovery',\n sourceRefs: [\n 'saas-technical-doc:engine-content/sso-rollout-and-recovery',\n 'source:consumer-fact:access-single-sign-on',\n ],\n markdown: `# Roll out SSO and keep a recovery path\n\nIntroduce a configured connection in stages so a mapping mistake or provider\noutage cannot lock every administrator out at once.\n\n| Before you begin | Successful result |\n| --- | --- |\n| The connection passes a controlled test, the application and identity-provider owners are available, and an independent administrator can enter without this connection | Representative people sign in to the right organization with expected access, the connection becomes default only after proof, and a tested recovery path remains available |\n\nThe application can offer more than one configured connection and distinguish\nenabled from default behavior:\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#markdown}}\n\n~~~mermaid\nflowchart LR\n accTitle: Roll out single sign-on in controlled stages\n accDescr: Keep an independent recovery administrator, test one controlled identity, expand to a representative pilot, make the connection default only after verification, and retain the recovery path.\n recovery[\"Verify independent administrator recovery\"] --> controlled[\"Test one controlled identity\"]\n controlled --> pilot[\"Expand to a representative pilot\"]\n pilot --> default[\"Make default after verification\"]\n default --> monitor[\"Monitor and retain recovery\"]\n controlled -.-> stop[\"Stop on unexplained difference\"]\n pilot -.-> stop\n~~~\n\nThe recovery identity must not depend on the connection being tested. Confirm it\nbefore changing the default connection, and verify it again after a material\nprovider or trust change.\n\n## Build a representative pilot\n\nDo not test only an administrator. Include the identity and access differences\nthat can reveal a mapping defect:\n\n| Pilot case | What it proves |\n| --- | --- |\n| Existing ordinary member | Stable subject mapping does not create a duplicate person |\n| Newly eligible person, when first-sign-in creation is enabled | The intended user and membership lifecycle occurs with the fallback role |\n| Person with a mapped provider role or group | The exact external value maps to the intended application role |\n| Person outside an allowed domain or mapping | The connection refuses the identity without revealing another account |\n| Person with application MFA requirements | The actual post-provider journey is observed; do not infer it from the currently non-operative \\`bypassAppMFA\\` field |\n| Independent recovery administrator | Provider outage or mapping failure does not remove all administrative access |\n\nUse controlled test identities and non-sensitive application actions. Do not\nalter a real person's provider attributes merely to make the pilot pass.\n\n## Run the staged rollout\n\n1. Test one controlled identity whose provider attributes and organization\n membership are already known.\n2. Confirm the person returns to the correct environment and organization.\n3. Verify expected application access and an expected refusal; a successful\n provider login alone is insufficient.\n4. Expand to a pilot representing the identity patterns and roles used by the\n organization.\n5. Stop on an unexplained mapping, membership or access difference.\n6. Confirm how leavers and role changes are handled manually or through SCIM;\n SSO alone does not close the application membership.\n7. Make the connection default only when the pilot and recovery path both pass.\n\n## Make the default change observable\n\nChoose a support window, communicate which people and organization are affected,\nand record the previous default connection. After the change, repeat a normal\napplication-started sign-in rather than reusing a provider URL. Verify the\nresolved person, organization, expected action and expected refusal. Monitor\nauthentication failures separately from membership/role refusals so an access\nproblem is not mistaken for a provider outage.\n\n~~~mermaid\nstateDiagram-v2\n accTitle: Keep the connection in a known operational state\n accDescr: A connection begins configured but not default, advances through controlled and representative proof, becomes default only after recovery proof, returns to validation after any trust or mapping change, and is disabled when safe verification cannot be restored.\n [*] --> ConfiguredNotDefault\n ConfiguredNotDefault --> ControlledProof: one known identity passes\n ControlledProof --> Pilot: representative identities pass\n Pilot --> Default: recovery path also passes\n Default --> ConfiguredNotDefault: trust, credential, certificate, mapping or provider change\n ConfiguredNotDefault --> Disabled: validation cannot be completed safely\n Default --> Disabled: active incident requires containment\n Disabled --> ConfiguredNotDefault: corrected configuration is ready to retest\n~~~\n\nThe loop back to validation is intentional. A renewed secret, signing\ncertificate, issuer, endpoint, claim mapping or default role changes the trust\nor access proof even when the connection keeps the same display name.\n\n## Renew credentials and signing certificates without an outage\n\n### Rotate an OIDC client secret\n\n1. Confirm whether the provider supports two simultaneously valid secrets.\n2. Create the replacement in the provider and record its owner and expiry.\n3. Update the protected, write-only client-secret field in the matching\n application environment. Never paste the secret into a change ticket.\n4. Run a fresh controlled sign-in and inspect both provider and application\n evidence.\n5. Revoke the previous secret only after the replacement succeeds and the\n rollback window has been approved.\n\nIf the provider permits only one active secret, schedule a support window,\nretain the independent administrator path, update both sides as one controlled\nchange, and test immediately.\n\n### Rotate a SAML signing certificate\n\n1. Obtain the provider's new public signing certificate and verify its\n fingerprint through an approved independent channel.\n2. When the provider and application support overlapping certificates, load the\n new certificate before the provider starts signing with it.\n3. Run **Test connection**, then complete a real sign-in.\n4. Switch the provider to the new signing key and repeat the controlled proof.\n5. Remove the old certificate only after all provider nodes use the new key and\n the overlap window has ended.\n\nThe application schema accepts more than one SAML signing certificate so a\nplanned overlap is possible. Do not replace a certificate merely because a\nticket contains a PEM block; verify the provider source and fingerprint.\n\n## Monitor both sides of the boundary\n\nCorrelate by time, person, application/connection and the provider's request or\ncorrelation identifier where available. Provider success plus application\nfailure points to response validation, mapping or membership. Provider failure\nmeans the application may never receive a response.\n\n- Microsoft Entra: [sign-in logs](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-ins)\n and [sign-in diagnostics](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-use-sign-in-diagnostics).\n- Okta: [System Log](https://help.okta.com/en-us/content/topics/reports/reports_syslog.htm).\n- Google Workspace: use the provider's authentication and SAML application\n audit/investigation views available for the organization's edition, together\n with the application audit trail.\n\n## Prepare for provider or configuration failure\n\nRecord who owns the provider and application sides of the connection, how to\nreach the independent recovery method, and which last-known-good values can be\ncompared without exposing secrets. After changing issuer, entity, audience,\nredirect, certificate, client or mapping settings, repeat the controlled test\nbefore expanding again.\n\nIf the provider is unavailable, use the independent recovery method, confirm\nthe scope of the outage and avoid changing trust values speculatively. Restore\nor correct one boundary, retest with a controlled identity, then return the\nconnection to default use. Keep the recovery method narrow and monitored; it is\nnot a shared bypass account.\n\nRetain the connection name, organization, environment, pilot cases, test times,\nnon-secret trust identifiers, mapping decisions, allowed/refused results,\ndefault-change approval and recovery proof. Exclude passwords, one-time codes,\nclient secrets, private keys, complete assertions and session cookies.`,\n },\n {\n managedPath: 'access-and-identity/sso-troubleshoot.md',\n unitRef: 'technical-documentation:unit/sso-troubleshoot',\n sourceRefs: [\n 'saas-technical-doc:engine-content/sso-troubleshoot',\n 'source:consumer-fact:access-single-sign-on',\n ],\n markdown: `# Troubleshoot single sign-on\n\nAn SSO failure can occur before the person reaches the identity provider, while\nthe provider authenticates them, when the application validates the returned\nresponse, or after sign-in when membership and roles are evaluated. Find that\nboundary first. Changing trust settings before you know the boundary can turn a\nlocal mapping problem into an outage for everyone using the connection.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Have an independent administrator recovery method, one controlled test identity, the environment, organization, connection name and approximate failure time | The failing stage and responsible configuration are identified, one narrow correction is verified, and the recovery path still works |\n\n## Locate the failing stage\n\n~~~mermaid\nflowchart TD\n accTitle: Locate a single sign-on failure without weakening trust\n accDescr: The administrator confirms that the application offers the intended connection, checks whether the identity provider accepted the request, verifies the returned response against the configured trust, then diagnoses identity mapping, organization membership and roles separately.\n start[\"Person starts from the application sign-in page\"] --> offered{\"Intended connection offered?\"}\n offered -->|No| selection[\"Check enabled state, default choice, organization and environment\"]\n offered -->|Yes| provider{\"Provider accepts request and authenticates person?\"}\n provider -->|No| providerConfig[\"Check provider-side client or service configuration\"]\n provider -->|Yes| response{\"Application accepts returned response?\"}\n response -->|No| trust[\"Check issuer or entity, audience, destination, signature and time\"]\n response -->|Yes| identity{\"Correct person and organization?\"}\n identity -->|No| mapping[\"Check stable identity mapping and membership\"]\n identity -->|Yes| access{\"Expected operation allowed?\"}\n access -->|No| authorization[\"Check membership, role and operation contract\"]\n access -->|Yes| complete[\"Record successful controlled proof\"]\n~~~\n\nStart from the application's normal sign-in page. It is the authority for the\nconnections available to this person and organization:\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#markdown}}\n\nAn enabled connection may be offered for use; a default connection may be\nselected automatically. Neither setting proves that the provider trust,\nidentity mapping or organization access is correct.\n\n## Read the symptom by boundary\n\n| Symptom | Check first | Safe response |\n| --- | --- | --- |\n| The connection is not offered | Enabled state, organization and environment | Use the application's sign-in journey; do not construct a callback URL |\n| The provider rejects the request | Provider/application identity and registered destination | Correct the matching environment's configuration |\n| The application rejects the response | Signature trust, issuer/entity, audience, timing and intended connection | Treat it as a trust failure; never disable validation |\n| Sign-in resolves the wrong person | Stable subject and identity mapping | Correct the mapping; do not match only by display name |\n| Sign-in succeeds in the wrong organization | Connection scope and membership | Select or correct the intended organization relationship |\n| Sign-in succeeds but an action is refused | Membership state, role and exact operation | Diagnose authorization separately from SSO |\n\nFor **OpenID Connect**, compare the published issuer, client identity, exact\nreturn destination and client authentication configuration for the same\nenvironment. For **SAML**, compare the provider and application entity\nidentities, response destination, audience and current signing trust. In both\nprotocols, a value from staging is not interchangeable with its production\ncounterpart even when the display names look similar.\n\n## Compare both sides before changing anything\n\n| Evidence | Provider side | Application side | What a mismatch means |\n| --- | --- | --- | --- |\n| Request destination | The app integration that received the request | Configured authorization or SSO URL | Wrong tenant, provider application or environment |\n| Return destination | Registered redirect URI or ACS URL | Current environment callback/ACS value | Provider will refuse the request or application will reject the response |\n| Trust identity | OIDC issuer or SAML IdP entity ID | Connection issuer/entity ID | Response came from a different trust boundary |\n| Intended recipient | Provider app/client or SAML audience configuration | OIDC client ID or SAML service-provider identity | Response was issued for another application |\n| Signing material | Current JWKS or SAML signing certificate | Resolved keys or configured certificates | Rotation drift, stale metadata or wrong provider |\n| Person mapping | Provider subject and mapped claims/attributes | Application identity/attribute mapping | Duplicate, missing or wrong person |\n| Access | Provider app assignment/groups | Membership, role mapping and application operation | Authentication succeeded but authorization is different |\n\nUse sanitized identifiers and fingerprints for comparison. Do not attach an ID\ntoken, SAML assertion, authorization code, client secret or session cookie.\n\n### OIDC checks\n\n- Resolve the exact issuer used by the connection and compare it byte-for-byte\n with the provider metadata for this tenant or authorization server.\n- Confirm the provider app registration contains the exact web redirect URI for\n this environment. A path, scheme, host or trailing-slash difference can be a\n different URI.\n- Confirm the client secret is current at both sides. A masked read proves only\n that a value is stored, not that it is the provider's active credential.\n- Confirm the authorization-code journey uses PKCE S256 and that the code is\n redeemed only once by the same environment.\n- Check whether the response supplies the configured email, subject and\n optional group/role claims. Correct the provider claim or mapping; never map a\n display name as the stable subject.\n\nThe application verifies an OIDC ID token's signature, issuer, audience,\nexpiration and issued-at claims when the connection resolves both a signing-key\nlocation and issuer. If either is absent, profile retrieval can follow a\ndifferent provider path, so preserve the exact connection mode in support\nevidence.\n\n### SAML checks\n\n- Compare the provider entity ID, application/service-provider entity ID, ACS\n destination and assertion audience as four distinct values.\n- Verify the response is signed by a certificate currently trusted on the\n connection and that the certificate is within its validity window.\n- Check server time before increasing clock tolerance. The supported tolerance\n is 0–300 seconds and defaults to 30 seconds; it is not a substitute for clock\n synchronization.\n- For provider-started sign-in, confirm \\`allowIdpInitiated\\` is deliberately\n enabled. The application validates the signature against matching connection\n candidates and refuses an ambiguous tenant match rather than guessing.\n- Check NameID and attribute mappings separately. A valid NameID does not prove\n that the required email or role/group attribute is present.\n\n{{CONSUMER_FACT:source:consumer-fact:access-single-sign-on#diagnosticsMarkdown}}\n\n## Use provider logs to locate the hand-off\n\n- [Microsoft Entra sign-in logs](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-ins)\n show the person, application, target resource and provider result. Use\n [sign-in diagnostics](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/howto-use-sign-in-diagnostics)\n for a failed event.\n- [Okta System Log](https://help.okta.com/en-us/content/topics/reports/reports_syslog.htm)\n exposes time, actor, target and event details for the provider side.\n- For Google Workspace or Cloud Identity, inspect the organization's SAML or\n authentication audit/investigation view for the affected custom app and time.\n\nIf the provider has no matching attempt, investigate connection selection and\nthe outbound request. If the provider records success but the application has\nno accepted session, investigate return destination and response validation.\nIf both record success, move to identity mapping, membership and roles.\n\n## Test one correction safely\n\n1. Preserve the last-known-good non-secret identifiers before editing.\n2. Change one configuration boundary at a time.\n3. Start a fresh sign-in from the application with the controlled identity; do\n not replay an old response or reuse a callback URL.\n4. Verify the resolved person, organization and one expected allowed action.\n5. Verify an expected refusal so the test does not prove over-broad access.\n6. Confirm the independent recovery administrator can still enter.\n\nA completed provider login proves only that the provider accepted the person.\nIt does not prove that the application accepted the response or that the\nperson's organization membership and role authorize the requested work.\n\n## Escalate without exposing credentials\n\nPreserve the time, environment, organization, connection name, protocol,\nfailing stage, sanitized message and correlation identifier. State whether one\nperson or all tested people are affected and whether the connection ever\nworked in this environment. Do not collect a password, one-time code, private\nkey, client secret, complete certificate chain, authorization code, session\ncookie or full SAML/OIDC response in an ordinary ticket.\n\nUse the independent recovery method if administrators cannot enter through SSO.\nRestore or correct the connection, retest with the controlled identity, and only\nthen return it to default use. SSO recovery must not create a new membership or\nbroaden a role merely to make the sign-in test pass.`,\n },\n {\n managedPath: 'access-and-identity/api-keys.md',\n unitRef: 'technical-documentation:unit/api-keys',\n sourceRefs: [\n 'saas-technical-doc:engine-content/api-keys',\n 'source:consumer-fact:access-api-keys',\n ],\n markdown: `# API keys\n\nAPI keys authenticate unattended software such as a server, scheduled job or\nautomation. They do not represent a signed-in person and do not bypass roles,\norganization boundaries, feature state or an operation's API-key policy.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Name one workload, owner, environment, organization/application scope and minimum set of operations | The workload has one independently revocable credential, performs only its intended work and leaves non-secret evidence that can be reviewed |\n\n## Choose a machine identity deliberately\n\n| Need | Use | Avoid |\n| --- | --- | --- |\n| One unattended workload acts inside one organization | Organization API key when the exact operations accept it | A person's session or an application-wide key |\n| One trusted workload genuinely needs application-wide operations | Application API key when those operations explicitly accept it | Promoting an organization key after an unexplained 403 |\n| A client acts after a person authorizes it | [OAuth delegated access](/access-and-identity/oauth-provider) | Collecting the person's password or reusing their browser session |\n| A person works interactively | Their own [sign-in method](/access-and-identity/sign-in-and-mfa) | An API key shared between people |\n\nThe credential type identifies **who is acting**. It does not decide what the\nidentity may do. Key scope, assigned roles, organization visibility, feature\nstate and the operation's authentication contract are all evaluated separately.\n\n~~~mermaid\nflowchart LR\n accTitle: Manage an API key through its lifecycle\n accDescr: Choose the smallest scope and roles, create and store the secret, deploy it to one workload, verify its use, rotate it deliberately, and deactivate it when no longer needed.\n choose[\"Choose scope and minimum roles\"] --> create[\"Create and store secret\"]\n create --> verify[\"Verify one safe operation\"]\n verify --> rotate[\"Rotate deliberately\"]\n rotate --> deactivate[\"Deactivate when finished\"]\n~~~\n\nEvery key should have one understandable owner, workload, environment and\npurpose. If those cannot be identified during review, replace or deactivate the\ncredential rather than leaving anonymous production access active.\n\nThe lifecycle is operational, not merely cryptographic: somebody must know\nwhere the current secret is deployed, how to prove a replacement, when the\nprevious secret stops working and how to deactivate the key during an incident.\n\n## Follow the API-key journey\n\n| Your next task | Start here | Successful result |\n| --- | --- | --- |\n| Choose scope and create a key | [Create and store an API key](/access-and-identity/api-keys-create-and-store) | One independently identifiable key can perform only the intended operations |\n| Replace a key or end its access | [Rotate, expire or deactivate an API key](/access-and-identity/api-keys-lifecycle) | Workloads move to the intended secret and the previous access ends when expected |\n| Investigate a refused request | [Troubleshoot an API key](/access-and-identity/api-keys-troubleshoot) | Transport, lifecycle, scope and authorization failures are distinguished without broadening access |\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#markdown}}\n\nThe prefix identifies scope; it does not grant authority. The key's roles and\nthe requested operation remain decisive.\n\n## Understand the two scopes and three states\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#scopeComparisonMarkdown}}\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#statusMarkdown}}\n\nThe HTTP standard defines the [\\`Authorization\\` request field](https://www.rfc-editor.org/rfc/rfc9110#field.authorization),\nwhile OAuth bearer tokens use the separate [\\`Bearer\\` authentication scheme](https://www.rfc-editor.org/rfc/rfc6750#section-2.1).\nThis application's API-key contract uses the \\`Authorization\\` field with the\nraw key and **no scheme**. Treat that as application-specific wire syntax: do\nnot prepend \\`Bearer\\`, put the key in a query string, or rename the field.\n\n## Review every key as access\n\nAt creation and at each review, record:\n\n- the accountable owner and workload;\n- environment and organization/application scope;\n- intended operations and minimum assigned roles;\n- non-secret key prefix, status, expiry and the available application/workload\n evidence (the current runtime does not populate per-key last-used statistics);\n- secrets-manager location and deployment owners;\n- rotation/deactivation procedure and next review date.\n\nDo not retain the complete key in that record. If a key is unused, ownerless,\ndeployed to an unknown number of workloads or broader than its documented\npurpose, replace or deactivate it rather than accepting the ambiguity.`,\n },\n {\n managedPath: 'access-and-identity/api-keys-create-and-store.md',\n unitRef: 'technical-documentation:unit/api-keys-create-and-store',\n sourceRefs: [\n 'saas-technical-doc:engine-content/api-keys-create-and-store',\n 'source:consumer-fact:access-api-keys',\n ],\n markdown: `# Create and store an API key\n\nCreate a separate machine credential for one workload and environment. This\ntask is for the integration owner and the administrator authorized to choose its\nscope and roles.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Know the workload owner, environment, required organization scope and minimum operations | The secret is stored outside code and a safe request proves only the intended access |\n\n~~~mermaid\nflowchart TD\n accTitle: Create and hand over one least-privilege API key\n accDescr: The integration owner defines one workload and scope, the administrator assigns minimum roles and an expiry or review date, the one-time secret is stored directly in a secrets manager, the workload performs a safe positive and negative proof, and only non-secret evidence is retained.\n workload[\"Name one workload, owner and environment\"] --> scope[\"Choose organization or application scope\"]\n scope --> roles[\"Assign minimum roles for documented operations\"]\n roles --> create[\"Create key with expiry or review date\"]\n create --> store[\"Store one-time secret directly in secrets manager\"]\n store --> deploy[\"Deploy to the one owning workload\"]\n deploy --> proof[\"Verify intended success and expected refusal\"]\n proof --> evidence[\"Retain prefix, owner and lifecycle evidence\"]\n~~~\n\nThe diagram deliberately has no “copy to a ticket” or “send to another team”\nstep. The complete secret should move from the creation response to protected\nstorage and then to the owning workload through its normal secret-delivery path.\n\n## Choose the smallest scope\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#markdown}}\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#scopeComparisonMarkdown}}\n\n- Choose an **organization key** for a workload acting inside one organization.\n- Choose an **application key** only for a workload that genuinely needs\n application-wide scope and whose operation contracts accept it.\n\nDo not select application scope merely because an organization key receives a\nrefusal. First verify the role, feature and operation contract.\n\nBefore creation, list the exact business operations the workload performs and\nmap each to its API reference authentication/role contract. Remove speculative\nfuture permissions. When operations span unrelated purposes, create separate\nkeys so one workflow can be rotated or contained without interrupting another.\n\n## Name and create the credential\n\nUse a name that identifies the system, environment and purpose—for example\n“Production invoice reconciliation”. Record its accountable owner, intended\noperations, assigned roles, expiry or review date. Do not share one key between\nunrelated workloads: independent keys make rotation, incident containment and\naudit attribution possible.\n\nThe complete secret is returned at creation and may not be recoverable later.\nMove it directly into the workload's secrets manager. Keep only its visible\nprefix for ordinary identification. Never retain the full key in source code, a\nbrowser bundle, URL, screenshot, ticket or ordinary log.\n\nIf the creation response is lost before protected storage succeeds, do not ask\nsupport to recover the secret. Replace the credential through the approved\nlifecycle, record the abandoned prefix and ensure the unusable key is inactive.\n\n## Deliver the secret through the workload's secret system\n\nChoose the system that already controls secrets for the workload. Do not add a\nnew copy merely to follow this guide.\n\n| Workload | Safe delivery pattern | What to verify |\n| --- | --- | --- |\n| AWS-hosted service | Store the value in AWS Secrets Manager and let the workload retrieve it through a narrow workload identity | Only the owning workload can read the secret; retrieval and rotation are monitored. See [AWS Secrets Manager best practices](https://docs.aws.amazon.com/secretsmanager/latest/userguide/best-practices.html). |\n| Azure-hosted service | Store the value in Azure Key Vault, separate application/environment boundaries and attach owner/expiry metadata outside the value | The workload identity can read this secret but cannot administer the vault. See [Azure Key Vault secret guidance](https://learn.microsoft.com/en-us/azure/key-vault/secrets/secure-secrets). |\n| Google Cloud workload | Store the value in Secret Manager in the workload's environment project and grant the minimum IAM access to that secret | Production and non-production projects and identities remain separate. See [Google Secret Manager best practices](https://docs.cloud.google.com/secret-manager/docs/best-practices). |\n| Kubernetes workload | Prefer an approved external secret store; otherwise encrypt Secrets at rest, restrict RBAC and expose the value only to the container that needs it | No manifest or base64 value enters source control, and unrelated containers cannot read it. See [Kubernetes Secrets good practices](https://kubernetes.io/docs/concepts/security/secrets-good-practices/). |\n| GitHub Actions workflow | Use an environment or repository secret restricted to the intended workflow/environment | The value is referenced through the secrets context and never echoed; log redaction is treated as defense in depth, not proof of non-disclosure. See [GitHub Actions secrets](https://docs.github.com/en/actions/concepts/security/secrets). |\n\nThe [OWASP Secrets Management guidance](https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html)\ndescribes the broader lifecycle: centralized ownership, least-privilege access,\nautomated delivery, rotation, revocation, expiry, auditing and recovery. Use the\napplication lifecycle below as the credential-side half of that operating model.\n\n## Send and verify the key\n\nSend the complete opaque value in the standard header, without a \\`Bearer\\`\nscheme:\n\n~~~text\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#requestHeader}}\n~~~\n\nUse an operation whose generated API reference explicitly permits API-key\naccess. Verify a safe read in the correct environment and organization before\nenabling writes.\n\nWith the base URL and key injected by the deployment system, a first read has\nthis shape. Replace \\`<operation-path>\\` with the exact path from the generated\nAPI reference; do not paste a real key into the command or shell history.\n\n~~~bash\ncurl --request GET \\\\\n --url \"$APPLICATION_API_BASE/<operation-path>\" \\\\\n --header \"Accept: application/json\" \\\\\n --header \"Authorization: $APPLICATION_API_KEY\"\n~~~\n\nThe workload variable must contain the complete organization- or\napplication-scoped value described by the source-derived table above. A\n\\`Bearer\\` prefix changes the bytes and causes authentication to fail.\n\nThen verify an expected refusal: choose an operation outside the intended role\nwithout probing another customer's known identifier. The successful read proves\nconnectivity; the refusal proves that the key did not receive broader authority\nthan intended.\n\n## Complete the handover\n\n1. Confirm every workload instance reads the intended secrets-manager version.\n2. Confirm ordinary logs show operation, outcome and correlation evidence but\n never the Authorization header.\n3. Record the key's non-secret prefix, owner, scope, roles, expiry/review date\n and deployed workload.\n4. Prove the owner can rotate and deactivate the key without affecting an\n unrelated integration.\n\nDo not enable production writes until this handover is repeatable.`,\n },\n {\n managedPath: 'access-and-identity/api-keys-lifecycle.md',\n unitRef: 'technical-documentation:unit/api-keys-lifecycle',\n sourceRefs: [\n 'saas-technical-doc:engine-content/api-keys-lifecycle',\n 'source:consumer-fact:access-api-keys',\n ],\n markdown: `# Rotate, expire or deactivate an API key\n\nReplace a machine credential without losing control of which secret works. Use\nrotation for a planned, bounded handover; use immediate rotation or deactivation\nfor suspected exposure; and use expiry when access has a known end date.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Identify the key by its non-secret prefix, owner, workload, scope, roles and deployed instances; have an approved secrets-manager destination | Every intended instance uses the replacement, the previous secret stops at the chosen time, expected access still works and unrelated access remains refused |\n\nThe key presentation identifies its scope, not its authority:\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#markdown}}\n\nConfirm that you are changing the intended organization or application key\nbefore reissuing any secret. A prefix is safe to use for identification, but it\nis not enough on its own: compare the owner, workload and environment too.\n\n## Choose the lifecycle action\n\n| Situation | Action | Important consequence |\n| --- | --- | --- |\n| Planned replacement with a short deployment window | **Rotate** with an explicit future invalidation time | Current and previous secrets can overlap only until that chosen time |\n| Suspected disclosure and the workload can switch now | **Rotate immediately** | Immediate rotation is the default when no future invalidation time is chosen; the previous secret stops working at cutover |\n| Suspected disclosure and workload ownership is uncertain | **Deactivate** | Neither the current nor retained previous secret can authenticate while the key is inactive |\n| Workload is permanently retired | **Deactivate** and remove its deployed secret | The key remains identifiable for review but cannot authenticate |\n| Temporary credential has a known end | Set an **expiry** at creation; extend it only after a documented review | Once expired, the key cannot be reactivated; replace it if access is approved again |\n| An intentional open-ended overlap is truly required | **Regenerate**, with a separately controlled follow-up rotation | The previous secret remains valid until a later reissue; regeneration does not contain a leaked credential |\n\n## Know the maintained lifecycle operations\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#statusMarkdown}}\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#lifecycleMarkdown}}\n\n~~~mermaid\nflowchart TD\n accTitle: Choose the safe API-key lifecycle action\n accDescr: A planned handover uses rotation and verification. Suspected compromise requires prompt old-secret invalidation or deactivation. Finished access is deactivated, while a time-bounded credential is allowed to expire.\n reason{\"Why must access change?\"}\n reason -->|\"Planned replacement\"| rotate[\"Rotate with explicit handover\"]\n reason -->|\"Suspected exposure\"| contain[\"Invalidate old secret promptly or deactivate\"]\n reason -->|\"Workload retired\"| deactivate[\"Deactivate key\"]\n reason -->|\"Known end time\"| expiry[\"Set or extend explicit expiry\"]\n~~~\n\n## Run a planned rotation\n\nRotation keeps the same credential record, owner, scope and roles while issuing\na new complete secret. The outgoing secret moves into a single previous-secret\nslot and remains usable only until the selected invalidation time. If no future\ntime is selected, the operation defaults to **now**, which is an immediate\ncutover.\n\n1. Inventory every production instance, scheduled job and deployment that reads\n this key. Do not rotate while ownership is unknown.\n2. Choose the shortest practical invalidation time. Record the reason, owner\n and planned end of overlap.\n3. Perform the rotation and move the one-time replacement directly into the\n approved secrets-manager entry. Never paste it into the change record.\n4. Roll out the new secret to every known instance and verify a safe operation\n in the intended environment and scope.\n5. Before the deadline, confirm every instance reports the replacement version\n and no deployment still depends on the outgoing secret.\n6. After invalidation, verify that the replacement still succeeds and that the\n previous secret is refused. Record only prefixes, times, outcomes and\n correlation evidence.\n\nIf an instance cannot move before the chosen time, stop and make a conscious\navailability-versus-exposure decision. Do not silently extend an overlap whose\nowner or purpose is unclear.\n\n## Understand regeneration before using it\n\n> **Regeneration is not incident containment.** An open-ended regenerate\n> operation leaves the previous secret valid until a later reissue replaces the\n> overlap state. If the key may be compromised, deactivate it or rotate with\n> prompt invalidation.\n\nRegeneration can support a deliberately staged migration when the old secret\ncannot yet have a bounded end time, but it creates two live secrets. Before\nusing it, document why a normal bounded rotation is impossible, who owns the\nfollow-up cutover and when the later rotation will occur. Verify both the new\ndeployment and the eventual rejection of the previous secret; issuing a new\nsecret is not completion.\n\n## Contain suspected exposure\n\nWhen a complete secret may have reached source control, a browser bundle, a\nticket, an ordinary log or an unauthorized person:\n\n1. Preserve non-secret time, environment, prefix and workload evidence.\n2. Deactivate the key when deployment ownership is uncertain, or rotate with\n immediate invalidation when the approved workload can switch safely.\n3. Remove the exposed value from every deployment and storage location. Treat\n source-history or log cleanup as a separate containment task; rotation alone\n does not remove copied material.\n4. Review the application audit trail and workload/provider logs for the\n affected period, using the key identifier, prefix, operation and correlation\n evidence—not the complete secret. Do not infer inactivity from the current\n per-key usage-statistics response.\n5. Restore only the minimum intended roles and operations with a protected\n replacement. Verify an expected refusal as well as a successful request.\n\n## Handle status and expiry\n\nAn inactive key cannot authenticate, including through a retained previous\nsecret. Reactivation is permitted only for an **Inactive** key; an **Expired**\nkey is terminal and cannot be reactivated. If access is approved again after\nexpiry, create a new least-privilege credential with a new review decision.\n\nExpiry is enforced when the key authenticates. Treat the key as unusable after\nthat time even if a list view has not yet changed its stored status label.\nExtend an existing expiry only when the same owner, workload, scope, roles and\nbusiness need have been reviewed. Extension changes the time boundary; it does\nnot rotate secret material or repair an ownerless key.\n\n## Close the change with evidence\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#usageStatisticsLimitationMarkdown}}\n\nUntil per-key tracking exists, prove deployment and retirement from controlled\nrequests, application audit evidence and the workload's own secret-access and\nexecution logs. A page of zero counters is not a safe deletion decision.\n\nRetain a non-secret lifecycle record containing:\n\n- key identifier or visible prefix, scope, owner and workload;\n- action taken, reason, approver and environment;\n- replacement deployment time and every affected instance;\n- chosen previous-secret invalidation time;\n- successful expected operation and expected refusal;\n- confirmation that the previous secret no longer authenticates; and\n- incident or change correlation identifier and next review date.\n\nNever attach the current or previous complete secret, Authorization header or\nsecrets-manager value to lifecycle evidence.`,\n },\n {\n managedPath: 'access-and-identity/api-keys-troubleshoot.md',\n unitRef: 'technical-documentation:unit/api-keys-troubleshoot',\n sourceRefs: [\n 'saas-technical-doc:engine-content/api-keys-troubleshoot',\n 'source:consumer-fact:access-api-keys',\n ],\n markdown: `# Troubleshoot an API key\n\nDiagnose the failed decision in order: transport, credential lifecycle, scope,\nrole and operation policy. Do not rotate or broaden a credential before you\nknow which decision failed.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Preserve the environment, operation, approximate time, correlation details and non-secret key prefix | One narrow correction makes a safe request succeed, and the workload still cannot exceed its intended scope |\n\n~~~mermaid\nflowchart TD\n accTitle: Diagnose an API key from transport to operation access\n accDescr: The integration owner confirms the environment and authorization header, matches the non-secret prefix to an active unexpired key, verifies organization or application scope and assigned roles, and finally checks whether the exact operation accepts API-key authentication.\n symptom[\"Request is refused or resource is missing\"] --> environment[\"Confirm environment and operation\"]\n environment --> transport{\"Header contains current opaque key?\"}\n transport -->|No| correct[\"Correct secret delivery without logging it\"]\n transport -->|Yes| lifecycle{\"Key active and unexpired?\"}\n lifecycle -->|No| replace[\"Use approved rotation or replacement\"]\n lifecycle -->|Yes| scope{\"Scope and roles match the task?\"}\n scope -->|No| assignment[\"Correct the narrow assignment\"]\n scope -->|Yes| contract[\"Check exact operation authentication contract\"]\n contract --> proof[\"Repeat one safe request and verify result\"]\n~~~\n\nThe non-secret prefix helps identify the credential record; it cannot prove\nthat the workload received the current complete secret.\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#usageStatisticsLimitationMarkdown}}\n\nDo not diagnose an apparently unused key from those counters. Correlate the\nworkload's execution logs, secret-access logs, application audit trail and one\ncontrolled request instead.\n\nThe request must carry the complete opaque value in this maintained header\nshape:\n\n~~~text\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#requestHeader}}\n~~~\n\n| Result | Check first | Safe response |\n| --- | --- | --- |\n| **401 Unauthorized** | Header spelling, complete secret, absence of \\`Bearer\\`, key status, expiry and environment | Correct transport or replace an inactive, expired or revoked key |\n| **403 Forbidden** | Key roles, scope, feature entitlement and whether the operation accepts API keys | Correct the narrow assignment or integration design |\n| **404 Not Found** | Resource identifier and organization visibility | Confirm scope without assuming a hidden resource exists |\n| Requests alternate between success and 401 | Secret version on every workload replica or job runner | Finish deployment of the current secret, then retire the previous one deliberately |\n\n## Isolate the failing decision\n\n1. Confirm the workload targets the expected environment.\n2. Confirm the standard authorization header contains the current complete\n opaque key and no scheme.\n3. Compare the non-secret prefix with the intended credential record.\n4. Check whether rotation recently created a new secret and whether every\n workload instance received it.\n5. Check active status and expiry. An expired or inactive key must not\n authenticate even if its record remains visible.\n6. Check organization or application scope and assigned roles.\n7. Check the exact operation's generated authentication contract. Some\n operations intentionally refuse API-key access.\n8. Repeat one read-only or otherwise safe request and verify the business result\n in the intended scope.\n\n## Choose the repair that matches the failure\n\n- **Transport failure:** correct the secrets-manager reference or header\n construction. Never print the value to compare it.\n- **Old secret after rotation:** deploy the new value everywhere and verify it\n before the previous value reaches its invalidation time.\n- **Inactive, expired or compromised key:** use the approved lifecycle action;\n do not reactivate a key whose owner or exposure is uncertain.\n- **Wrong scope or role:** change only the assignment needed by the documented\n workload. Re-run an expected refusal as well as the success proof.\n- **Operation rejects API keys:** use the supported human or delegated-client\n journey. A broader API key does not change the operation's authentication\n policy.\n\nNever replace a narrow key with a broadly privileged key merely to silence an\nauthorization error. That turns a diagnosable assignment problem into a larger\nsecurity exposure.\n\n## Escalate without exposing the credential\n\nProvide the environment, operation, HTTP result, approximate time, correlation\nidentifier, non-secret key prefix, lifecycle state and whether rotation was in\nprogress. Never include the complete key, authorization header, secret-manager\nvalue or a screenshot containing them.`,\n },\n {\n managedPath: 'access-and-identity/oauth-provider.md',\n unitRef: 'technical-documentation:unit/oauth-provider',\n sourceRefs: [\n 'saas-technical-doc:engine-content/oauth-provider',\n 'source:companion-projection:application-connection',\n 'source:consumer-fact:access-oauth-clients',\n ],\n markdown: `# OAuth provider and delegated access\n\nUse OAuth when software needs its own client identity or needs to act after a\nperson authorizes it. The integration does not receive the person's password or\ncopy their browser session.\n\nThis journey applies only when the application publishes an OAuth authorization\nserver. Its discovery metadata is authoritative for issuer identity, endpoints,\nsupported grants and onboarding. Do not construct those values from examples.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Know who owns the integration, which environment it runs in, whether it acts as itself or for a person, and which application operations it needs | One independently registered client uses the published flow, carries only the intended roles and can be reviewed or revoked without affecting another integration |\n\n## Choose whose authority the client uses\n\n~~~mermaid\nflowchart TD\n accTitle: Choose an OAuth client journey by who authorizes the work\n accDescr: A backend workload that acts as itself uses an advertised machine grant and its own client roles. A client that acts for a person uses the advertised authorization journey, exact registered redirects and user consent when required; the final operation remains bounded by the client and person.\n need{\"Whose authority should the integration use?\"}\n need -->|Its own machine identity| machine[\"Register a workload client\"]\n machine --> machineGrant[\"Use an advertised machine grant\"]\n machineGrant --> machineRoles[\"Authorize operations with client roles\"]\n need -->|A person authorizes the client| delegated[\"Register a delegated client\"]\n delegated --> redirect[\"Use exact redirects and the published browser flow\"]\n redirect --> consent[\"Person approves or denies when consent is required\"]\n consent --> combined[\"Operation is bounded by client roles and the person's context\"]\n~~~\n\n- Choose a **machine client** for a backend process whose work should be\n attributable to the integration itself. Do not use an administrator's\n personal browser session for unattended work.\n- Choose **delegated access** when the operation should remain connected to the\n person who approved it. The client must send the person through the published\n authorization journey; collecting their password is never an alternative.\n- Use an **API key** instead when the exact API operation supports that simpler\n machine credential and no OAuth delegation or client lifecycle is needed.\n\n## Understand the four independent decisions\n\n| Decision | What it controls | What it does not do |\n| --- | --- | --- |\n| Grant | Whether the client acts as itself or uses a person's authorization journey | It does not grant an application role |\n| Client class and token method | Whether the runtime can protect a secret and how it authenticates to the token endpoint | A public client does not become confidential by embedding a secret in shipped code |\n| Identity scopes | Which supported identity claims the client may request | They do not authorize business operations |\n| Roles | Which application operations the client may perform | They do not replace the person's membership in a delegated journey |\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#markdown}}\n\nThe client can belong to an organization or to the application. That scope\nchooses the machine identity and administrative boundary; it does not make a\nclient more trusted merely because it is application-scoped.\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#scopeComparisonMarkdown}}\n\nRegister a separate client for each integration and environment. Redirects,\nissuer identity and credentials are environment-specific security boundaries,\nnot values to normalize or copy between deployments.\n\n## Start from discovery, not guessed endpoint paths\n\nThe authorization server publishes two equivalent metadata entry points:\n\n- OAuth authorization-server metadata at\n \\`/.well-known/oauth-authorization-server\\`;\n- OpenID Connect discovery at \\`/.well-known/openid-configuration\\`.\n\nFetch one from the **API issuer origin** and use the absolute endpoint values it\nreturns. The authorization endpoint is a browser-facing application page; the\ntoken, key, user-information, revocation and logout endpoints belong to the API\nissuer. They are deliberately not all under one hand-constructed path.\n\n~~~bash\ncurl --fail --silent --show-error \\\n \"{{APPLICATION_CONNECTION_VALUE:oauthMetadataUrl}}\"\n~~~\n\nThat URL is not the issuer with the well-known segment appended, and the difference matters. RFC\n8414 inserts \\`/.well-known/oauth-authorization-server\\` **between the host and the issuer's path**,\nwhile OpenID Connect discovery appends its suffix to the issuer — the opposite construction. This\napplication's issuer is \\`{{APPLICATION_CONNECTION_VALUE:oauthIssuer}}\\`, and it serves the same\nmetadata document at both locations, so a client that derives either way finds it.\n\nCheck the returned \\`issuer\\` exactly. Then read the advertised grants,\n\\`code_challenge_methods_supported\\`, token authentication methods, registration\nendpoint and resource-indicator support before configuring the client. A\nmissing optional field means that capability is not advertised in this\nenvironment.\n\n~~~mermaid\nsequenceDiagram\n accTitle: Discover the authorization server before choosing a client flow\n accDescr: The integration starts from a resource or issuer, loads maintained metadata, selects only advertised registration and grant capabilities, and then uses the absolute endpoints returned by that metadata.\n participant Client as Integration client\n participant Resource as Protected resource\n participant AS as Authorization server\n Client->>Resource: Request protected operation\n Resource-->>Client: 401 plus protected-resource metadata when applicable\n Client->>Resource: Load protected-resource metadata\n Resource-->>Client: Authorization-server issuer and resource identifier\n Client->>AS: Load OAuth or OIDC metadata\n AS-->>Client: Issuer, endpoints, grants, PKCE and registration capabilities\n Client->>Client: Select supported registration and grant\n~~~\n\n## Use the protocol vocabulary consistently\n\n| Published element | Why the client needs it | Validation to retain |\n| --- | --- | --- |\n| \\`issuer\\` | Identifies the authorization server that produced the response and tokens | Exact string match; do not normalize hosts, paths or trailing slashes |\n| \\`authorization_endpoint\\` | Sends the person's browser through sign-in and consent | Use only the absolute discovered URL and preserve transaction state |\n| \\`token_endpoint\\` | Exchanges a machine credential, authorization code or refresh token | Use the registered client method and never log request credentials or returned tokens |\n| \\`jwks_uri\\` | Publishes public verification keys for signed tokens | Validate signature, algorithm, issuer, audience and time claims at the consuming service |\n| \\`resource\\` | Names the protected API, MCP server or A2A endpoint the token is meant for | Use the canonical advertised resource URI in both authorization and token requests when required |\n| \\`revocation_endpoint\\` | Ends a token authorization through the authenticated client lifecycle | Treat a successful no-oracle response as request acceptance, then verify the protected operation is refused |\n\nThe main standards behind those fields are [OAuth authorization-server metadata\n(RFC 8414)](https://www.rfc-editor.org/rfc/rfc8414), [PKCE (RFC\n7636)](https://www.rfc-editor.org/rfc/rfc7636), [OAuth resource indicators (RFC\n8707)](https://www.rfc-editor.org/rfc/rfc8707), [authorization-response issuer\nidentification (RFC 9207)](https://www.rfc-editor.org/rfc/rfc9207), [token\nrevocation (RFC 7009)](https://www.rfc-editor.org/rfc/rfc7009) and [OpenID\nConnect Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html).\nThe environment's metadata is still the authority for which optional\ncapabilities are enabled here.\n\n## When the protected resource is an MCP server\n\nDo not register an MCP client by guessing an OAuth endpoint. The [MCP\nauthorization specification](https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization)\nstarts from the protected resource, follows its RFC 9728 metadata to the\nauthorization server, and then chooses a registration mechanism in advertised\norder. In this application:\n\n1. use pre-registered client information when an administrator supplied it;\n2. use a Client ID Metadata Document only when metadata advertises support;\n3. use dynamic client registration only when a \\`registration_endpoint\\` is\n advertised; otherwise the route is intentionally unavailable;\n4. send the exact MCP endpoint as the RFC 8707 \\`resource\\` in the authorization\n and token requests.\n\nA dynamically registered client is deliberately **public, PKCE-only,\nauthorization-code-only, consent-required, role-free and identity-scope\nlimited**. That is an onboarding mechanism for a person-delegated MCP client,\nnot a way to mint an unattended privileged machine identity. Continue with the\n**MCP integration guide** — published under Integrations when the application\nexposes an MCP tool surface — for resource discovery and client setup.\n\n## Follow the OAuth client journey\n\n| Your next task | Start here | Successful result |\n| --- | --- | --- |\n| Define a new integration client | [Register an OAuth client](/access-and-identity/oauth-register-client) | One environment-specific client has the correct grant, class, roles and redirects |\n| Let a person authorize a client | [Authorize delegated access](/access-and-identity/oauth-authorize-delegated-access) | The person consents when required and the client receives no more authority than intended |\n| Review, rotate or revoke an active client | [Operate and revoke OAuth clients](/access-and-identity/oauth-operate-and-revoke) | Credential and authorization changes take effect without silently switching identities |\n\nBegin with the smallest safe proof: load the environment's discovery metadata,\ncomplete the selected flow with a controlled identity or workload, call one\nread-only operation and verify both the intended success and an expected\nrefusal. Do not add production writes until token storage, revocation,\nambiguous-outcome recovery and support ownership are defined.`,\n },\n {\n managedPath: 'access-and-identity/oauth-register-client.md',\n unitRef: 'technical-documentation:unit/oauth-register-client',\n sourceRefs: [\n 'saas-technical-doc:engine-content/oauth-register-client',\n 'source:consumer-fact:access-oauth-clients',\n ],\n markdown: `# Register an OAuth client\n\nCreate one client identity for one integration and environment. Record its\nowner, purpose, grant, roles, redirect URIs, token authentication method,\nconsent posture and review date.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Confirm that the application advertises an OAuth provider and choose whether the client acts as itself or after a person authorizes it | The registered client matches its runtime, can protect any required secret and uses only owned redirect destinations |\n\n~~~mermaid\nflowchart TD\n accTitle: Register one OAuth client with an explicit authority boundary\n accDescr: The integration owner identifies one environment and operating model, chooses a machine or delegated grant, protects a machine secret or classifies a delegated client as public or confidential, selects identity scopes and application roles separately, registers exact redirects, stores one-time secret material when applicable, and proves expected success and refusal.\n owner[\"Name integration owner, purpose and environment\"] --> authority{\"Acts as itself or for a person?\"}\n authority -->|\"Itself\"| machine[\"Choose an advertised machine grant\"]\n authority -->|\"For a person\"| delegated[\"Choose the advertised authorization journey\"]\n machine --> machineSecret[\"Protect the machine client secret\"]\n delegated --> clientClass[\"Choose public or confidential code client\"]\n machineSecret --> permissions[\"Separate identity scopes from application roles\"]\n clientClass --> permissions\n permissions --> redirects[\"Register exact owned redirects when interactive\"]\n redirects --> store[\"Protect one-time secret when confidential\"]\n store --> proof[\"Verify expected success and refusal\"]\n~~~\n\nRegister a separate client when the owner, environment, redirect surface or\nbusiness purpose differs. This preserves attribution and lets one integration\nbe rotated or retired without interrupting another.\n\n## Use an advertised onboarding path\n\nOAuth discovery is the authority for the current environment's provider\nidentity, supported grants and onboarding capabilities. An administrator-managed\nclient is approved inside the application. A dynamically registered client is\nself-described and receives a more cautious trust posture; use dynamic\nregistration only when the environment advertises it and the client can follow\nthe complete published flow. Do not probe an undocumented registration route.\n\n## Choose the allowed grant and client class\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#markdown}}\n\nChoose the administrative scope before choosing grants:\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#scopeComparisonMarkdown}}\n\nThe client form carries the following maintained security meanings. The API\nreference remains authoritative for the exact request shape and route in this\napplication.\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#clientConfigurationMarkdown}}\n\nUse a supported machine-to-machine grant when a backend service acts as itself.\nUse a supported authorization-code journey when a web, native, CLI or agent\nclient acts after a person authorizes it.\n\n- A **machine client** authenticates with its issued client secret. Run it only\n where that secret can be protected and delivered through a secrets manager.\n- A delegated **public client** cannot safely retain a client secret—for example browser\n or installed software. Use the published proof mechanism instead of embedding\n a pretend secret in the client package.\n- A delegated **confidential client** runs where its secret can be protected. Store that\n secret in a server-side secrets manager and authenticate to the token endpoint\n using the configured method.\n\n| Registration decision | Record | Common error |\n| --- | --- | --- |\n| Grant | Machine identity or person-delegated journey | Enabling every grant “for flexibility” |\n| Application roles | Minimum operations the client itself may perform | Treating identity scopes as permissions |\n| Identity scopes | Minimum identity claims needed by delegated sign-in | Requesting claims unrelated to the integration |\n| Delegated client class | Public when secret retention is impossible; confidential when server-side storage is real | Shipping a confidential secret in browser, native or distributed code |\n| Consent | Whether a person must approve this delegated client | Assuming consent can grant an administrator role |\n| Expiry/review | Known end date or accountable review date | Leaving an ownerless client active indefinitely |\n\n## Register redirect destinations exactly\n\nFor an authorization-code client, every redirect URI is an exact allowlist\nentry. Register only destinations owned by this client and environment. Never\nadd a wildcard, fragment, embedded credentials or a redirect copied from another\nenvironment. Ordinary web redirects use HTTPS; development or native forms are\nappropriate only when accepted by the administration surface and protected by\nthe published flow.\n\nRegister post-sign-out destinations separately when the client uses the\npublished sign-out journey. A sign-in return destination is not automatically a\nsafe sign-out destination. For a native client, use the supported loopback or\nprivate-application callback owned by that client and retain the transaction\nproof required by the published flow.\n\n> **A redirect URI is a security boundary, not a convenience pattern.** Review\n> its scheme, host, port and path as one exact value. Never broaden the allowlist\n> to repair an environment mismatch.\n\n### Choose a registration path deliberately\n\n| Registration path | Use it when | Trust and lifecycle consequence |\n| --- | --- | --- |\n| Administrator-managed registration | The integration has a known organization/application owner and may need machine roles or a confidential secret | An authorized administrator vouches for the client, chooses its roles and owns rotation/removal |\n| Client ID Metadata Document | A compatible client hosts maintained HTTPS metadata and discovery advertises support | The URL is the client identifier; the authorization server retrieves and validates its metadata under the deployment trust policy |\n| Dynamic client registration | Discovery exposes \\`registration_endpoint\\` and an interoperable public client needs fallback onboarding | Anonymous registration is rate-limited and confined to public authorization code, PKCE, identity scopes, explicit consent and no roles |\n\nDynamic registration follows [RFC 7591](https://www.rfc-editor.org/rfc/rfc7591),\nbut it is **off unless advertised**. A conforming request supplies a client name,\none or more safe exact redirect URIs and the authorization-code grant. The\naccepted response echoes the effective metadata. Read that response: a\nrequested refresh grant can be omitted by policy, and no client secret is\nissued on this path.\n\n## Verify the registered client\n\nConfirm the client record shows the intended grant, roles, identity scopes,\nredirects, consent setting and token authentication method. Keep the client\nidentifier and non-secret metadata with the integration configuration; keep any\nsecret only in protected storage.\n\nThe complete secret for a confidential client is one-time credential material.\nMove it directly into the approved secrets manager and deploy it only to the\nserver-side workload that owns this client. If that handoff is lost, reissue the\nsecret through the supported lifecycle; do not ask support to recover it.\n\nComplete a controlled proof before production use:\n\n1. Load discovery metadata for the exact environment.\n2. Complete the chosen grant using the registered class and redirect behavior.\n3. Verify the resolved client, person when delegated, organization and one safe\n expected application operation.\n4. Verify one operation outside the intended roles remains refused without\n probing another customer's known identifier.\n5. Confirm logs retain client identity, outcome and correlation evidence but no\n secret, authorization code or token.\n\nRecord the client identifier, owner, environment, registration origin, grant,\nclass, roles, identity scopes, redirect inventory, consent posture, expiry or\nreview date and secrets-manager owner.`,\n },\n {\n managedPath: 'access-and-identity/oauth-authorize-delegated-access.md',\n unitRef: 'technical-documentation:unit/oauth-authorize-delegated-access',\n sourceRefs: [\n 'saas-technical-doc:engine-content/oauth-authorize-delegated-access',\n 'source:consumer-fact:access-oauth-clients',\n ],\n markdown: `# Authorize delegated access\n\nUse delegated authorization when a client acts in a person's context without\nreceiving that person's password or session.\n\n| Before you begin | Successful result |\n| --- | --- |\n| The client is registered for the advertised delegated grant, exact return destination and appropriate public/confidential method; the person knows which client is requesting access | The person can approve or deny an understandable request, the client receives a token only through its own transaction, and the resulting operation is bounded by both client and person |\n\nThe maintained client contract separates supported grants, identity claims,\napplication roles, exact redirects and consent:\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#markdown}}\n\n~~~mermaid\nsequenceDiagram\n accTitle: Authorize a client without sharing a password\n accDescr: The person starts in the client, follows the application's published authorization flow, signs in and consents when required, and the client exchanges the returned code using the registered redirect and token method.\n participant Person\n participant Client as Third-party client\n participant App as Application\n Person->>Client: Start connected task\n Client->>App: Begin published authorization flow\n App->>Person: Sign in and request consent when required\n Person->>App: Approve or deny\n App-->>Client: Return to exact registered redirect\n Client->>App: Exchange code through published token flow\n App-->>Client: Return delegated access token\n~~~\n\nThe browser journey proves the person and records their decision. The code\nexchange proves that the response belongs to the client transaction that\nstarted it. Neither step gives the client the person's reusable credential.\n\n## Explain the request before asking for approval\n\nThe authorization screen should let the person recognize:\n\n- the client asking for access and the application/environment involved;\n- the identity information requested;\n- the business task the client intends to perform;\n- the organization in which the resulting operation will occur; and\n- whether the authorization can later be reviewed or revoked.\n\nIf the client identity or request is unexpected, the safe result is **deny**.\nDenial is a valid completed decision, not an error to work around. The client\nmust not retry with broader scopes or a different identity merely to avoid it.\n\n## Keep claims and authority separate\n\n- **Identity scopes** select supported identity claims the client may request.\n- **Client roles** govern application operations.\n- **The person's membership and authority** remain part of the delegated\n decision.\n\nAdding identity scopes does not repair a refused application operation. Consent\nalso cannot make the client an administrator or grant more authority than the\nperson and client are intended to carry.\n\nFor example, allowing the client to receive an email identity claim does not\nauthorize it to administer users. Conversely, an application role accepted for\nthe client cannot make an inactive organization membership active. Diagnose\neach axis separately.\n\n## Complete and verify the flow\n\n1. Start from the client and the environment's published authorization metadata.\n2. Bind the authorization request to the browser transaction that started it.\n3. Let the person sign in using their own method.\n4. Present and preserve the consent decision when the client requires it.\n5. Return only to the exact registered redirect URI.\n6. Verify the returned issuer exactly and exchange the code using the registered\n client class and token method.\n7. Confirm the resulting client, person, organization and expected operation\n access.\n8. Confirm an operation outside the intended combined authority remains\n refused.\n\nThe following request skeleton shows the values that must remain bound to one\ntransaction. Obtain every endpoint from discovery and generate a new verifier,\nchallenge, state and nonce for each attempt.\n\n~~~text\nGET {authorization_endpoint}?\n response_type=code&\n client_id={registered_client_id}&\n redirect_uri={exact_registered_redirect_uri}&\n code_challenge={base64url_sha256_of_verifier}&\n code_challenge_method=S256&\n state={unpredictable_transaction_value}&\n nonce={unpredictable_identity_token_value}&\n resource={canonical_protected_resource_uri}&\n scope=openid%20profile\n~~~\n\nAfter the redirect, first verify \\`state\\` and the returned \\`iss\\`. Exchange the\nsingle-use code at the discovered token endpoint with the **same** redirect,\nverifier, client and resource. Public clients send their client identifier and\nno secret; confidential clients also use the registered token-endpoint\nauthentication method.\n\n~~~bash\ncurl --fail --silent --show-error \\\n --request POST \"$OAUTH_TOKEN_ENDPOINT\" \\\n --header 'content-type: application/x-www-form-urlencoded' \\\n --data-urlencode 'grant_type=authorization_code' \\\n --data-urlencode \"client_id=$OAUTH_CLIENT_ID\" \\\n --data-urlencode \"code=$OAUTH_AUTHORIZATION_CODE\" \\\n --data-urlencode \"redirect_uri=$OAUTH_REDIRECT_URI\" \\\n --data-urlencode \"code_verifier=$OAUTH_CODE_VERIFIER\" \\\n --data-urlencode \"resource=$OAUTH_RESOURCE\"\n~~~\n\nThe variables above are process-local examples, not a recommendation to place\ntokens or client secrets in shell history. Use the workload's protected secret\nand token store for production delivery.\n\nAn issuer, redirect or transaction mismatch is a security failure. Restart the\npublished flow rather than normalizing the value or reusing a code from another\nattempt.\n\n## Handle interrupted and ambiguous journeys\n\n| Symptom | Safe response |\n| --- | --- |\n| Person closes or denies the request | Preserve the decision and return to the client without issuing authority |\n| Return destination does not exactly match | Stop; correct the registered client rather than redirecting manually |\n| Issuer or transaction proof differs | Discard the response and start a fresh application-published journey |\n| Code exchange is retried after an uncertain result | Reconcile client/token state; never reuse the same code as a generic retry |\n| Token succeeds but the business operation is refused | Check person membership, client roles and exact operation contract; do not add identity scopes |\n\nAfter success, verify the original business result in the application. A token\nresponse alone does not prove that a write happened once or that the client saw\nthe intended organization.\n\nRetain environment, client identifier, organization, requested identity scopes,\nconsent outcome, approximate time, operation result and correlation evidence.\nNever retain the person's password, session cookie, authorization code, complete\ntoken, client secret or full authorization response in an ordinary ticket.`,\n },\n {\n managedPath: 'access-and-identity/oauth-operate-and-revoke.md',\n unitRef: 'technical-documentation:unit/oauth-operate-and-revoke',\n sourceRefs: [\n 'saas-technical-doc:engine-content/oauth-operate-and-revoke',\n 'source:consumer-fact:access-oauth-clients',\n ],\n markdown: `# Operate and revoke OAuth clients\n\nReview active clients as independent machine identities. Keep each client,\ncredential and delegated token associated with its owner, environment, subject\nand organization.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Identify the client, owner, environment, grant, deployed workloads, delegated users and non-secret secret prefix; know whether the change concerns client configuration, client credential or issued tokens | The intended client or token access changes, expected operation and refusal are re-proven, and unrelated integrations continue without broader authority |\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#markdown}}\n\nThe maintained registered-client lifecycle is:\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#statusMarkdown}}\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#lifecycleMarkdown}}\n\n{{CONSUMER_FACT:source:consumer-fact:access-oauth-clients#currentUsageEvidenceMarkdown}}\n\n## Change the correct lifecycle layer\n\n~~~mermaid\nflowchart TD\n accTitle: Choose the OAuth lifecycle layer that needs to change\n accDescr: The operator distinguishes the registered client contract, its confidential secret, issued delegated tokens and the person's application membership, then changes and verifies only the affected layer.\n reason{\"What must change?\"}\n reason -->|\"Grant, roles, scopes, redirects or class\"| registration[\"Review or replace client registration\"]\n reason -->|\"Confidential secret\"| credential[\"Rotate with bounded invalidation\"]\n reason -->|\"One delegated authorization\"| token[\"Use published token revocation or reauthorization\"]\n reason -->|\"Person leaves organization\"| membership[\"Suspend/remove membership or use SCIM\"]\n registration --> verify[\"Repeat complete flow and authority proof\"]\n credential --> verify\n token --> verify\n membership --> verify\n~~~\n\nThese layers are related but not interchangeable. Rotating a client secret does\nnot by itself prove that an already issued delegated token is revoked. Removing\na person's organization access is a user-administration decision, not a reason\nto silently grant the client a machine role.\n\n## Review and change a client safely\n\nAt every review, answer these questions:\n\n- Is the owner and business purpose still current?\n- Does the grant still match who authorizes the work?\n- Are application roles limited to the exact operations still used?\n- Are identity scopes limited to claims the delegated client still needs?\n- Does every redirect and post-sign-out destination still belong to this client\n and environment?\n- Does the public/confidential classification match where the client now runs?\n- Is explicit consent still appropriate for the client's trust posture?\n- Do expiry, audit evidence, resource-server activity and active deployments\n support keeping it?\n\nA changed redirect, role, grant, identity scope, consent posture or token method\nchanges the security contract. Where the management surface does not safely\nsupport that transition in place, register a replacement client and migrate\ndeliberately instead of repurposing an established identity.\n\n## Rotate a confidential client secret\n\nRotate a confidential client secret through the administration operation\nprovided for that client. Deploy and verify the new secret before the previous\none becomes invalid when a handover is intended. For suspected compromise,\ninvalidate the previous secret promptly or remove the client; do not rely on\nan open-ended regenerate operation to contain exposure.\n\nRotation reissues the secret on the same client. A future invalidation time\ncreates a bounded overlap; the default is immediate invalidation. Regeneration\ncreates an open-ended overlap until a later reissue, so it is not incident\ncontainment.\n\n1. Inventory every workload instance using the confidential client.\n2. Choose the shortest practical invalidation time and record the owner.\n3. Store the one-time replacement directly in the approved secrets manager.\n4. Deploy it everywhere and complete a safe token plus operation proof.\n5. After invalidation, confirm the replacement succeeds and the previous secret\n is refused.\n\nIf disclosure is suspected and ownership is uncertain, remove the compromised\nclient through the supported administration lifecycle and register a protected\nreplacement. Do not leave an open-ended overlap while searching for consumers.\n\n## Revoke delegated access or retire a client\n\nUse the application's published token-revocation behavior when one delegated\nauthorization should end, and require a fresh authorization journey if the\nperson later restores it. Retire an entire integration by removing its client\nregistration and every deployed secret, then confirm new token issuance fails.\nSeparately suspend or remove the person's organization membership when their\napplication access must end; SSO or OAuth revocation alone is not the membership\nlifecycle.\n\nFor a suspected incident, treat client credential exposure and issued-token\nexposure as separate questions. Contain both applicable paths and review\nactivity for the affected client, person, organization and period.\n\nToken revocation follows [RFC 7009](https://www.rfc-editor.org/rfc/rfc7009): an\nunknown or already revoked token still receives a successful response so the\nendpoint does not become a token-validity oracle. Therefore **HTTP success is\nnot the final proof**. Retry one safe protected operation with the revoked token\nand verify that it is refused, then confirm a different unaffected client still\nworks. Confidential clients must authenticate to the revocation endpoint using\ntheir registered method; a bad client secret is refused before revocation.\n\n## Diagnose OAuth failures\n\n| Symptom | Check first | Safe response |\n| --- | --- | --- |\n| Discovery or registration is unavailable | Whether the capability is advertised here | Use an enabled onboarding path; do not probe undocumented endpoints |\n| Authorization request is rejected | Client, allowed grant, exact redirect and required proof | Correct the registered client or request |\n| Consent is denied or required | Client identity, claims and intended roles | Preserve the decision and explain or correct the request |\n| Code exchange fails | Issuer, redirect, proof, client class and token method | Restart the published flow; never reuse a code |\n| Token is valid but an operation is refused | Organization, client roles and person's authority | Diagnose authorization; do not request broader identity scopes |\n| Token is invalid or revoked | Client and token lifecycle | Refresh or reauthorize only through advertised behavior |\n\n## Close the change with non-secret evidence\n\nRetain the client identifier, non-secret secret prefixes, owner, environment,\ngrant, roles, identity scopes, redirect inventory, action and approval, old-\nsecret invalidation time, affected delegated authorization, successful expected\noperation, expected refusal and correlation evidence. Never attach a client\nsecret, authorization code, access/refresh token, Authorization header or\ncomplete authorization response.`,\n },\n {\n managedPath: 'user-administration.md',\n unitRef: 'technical-documentation:unit/user-administration',\n sourceRefs: [\n 'saas-technical-doc:engine-content/user-administration',\n ],\nmarkdown: `# 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.`,\n },\n {\n managedPath: 'user-administration/manage-users-manually.md',\n unitRef: 'technical-documentation:unit/manage-users-manually',\n sourceRefs: [\n 'saas-technical-doc:engine-content/manage-users-manually',\n 'source:consumer-fact:organization-membership-administration',\n ],\n markdown: `# Manage users manually\n\nUse this path when your organization manages people directly in the application.\nIt is the right starting point when you are not using SCIM to keep this group\nof users synchronized from an identity directory. The everyday job has three\nparts: bring someone in, keep their access correct, and take access away safely\nwhen it is no longer needed.\n\n~~~mermaid\nflowchart LR\n accTitle: Manual user membership lifecycle\n accDescr: A pending invitation can be accepted or revoked. An active membership can be suspended, reactivated, or removed.\n invite[\"Invite by email\"] --> invited[\"Invitation pending\"]\n invited -->|\"Accept\"| active[\"Active\"]\n invited -->|\"Revoke\"| invitationClosed[\"Invitation closed\"]\n active -->|\"Suspend\"| suspended[\"Suspended\"]\n suspended -->|\"Reactivate\"| active\n active -->|\"Remove\"| membershipEnded[\"Membership ended\"]\n~~~\n\n## See the lifecycle at a glance\n\n{{CONSUMER_FACT:source:consumer-fact:organization-membership-administration#markdown}}\n\nThe diagram is a decision aid, not an API reference. An invitation is pending\nuntil the person accepts it. A suspension is a deliberate, reversible hold. A\nremoval ends this organization membership. Pick the action that matches what\nyou want to happen, rather than treating every change as a delete.\n\n## Work through the three jobs in order\n\n1. [Invite and onboard a user](/user-administration/invite-and-onboard-user)\n explains how to send, resend or withdraw a pending invitation, and what to\n check after the person accepts it.\n2. [Change a user's access](/user-administration/change-user-access) explains\n how to review and adjust roles or organization-unit assignments without\n granting broad access by accident.\n3. [Suspend or remove a user](/user-administration/suspend-or-remove-user)\n explains the difference between a temporary hold, cancelling an unaccepted\n invitation, and permanently removing a membership.\n\n## Know when not to manage manually\n\nSingle sign-on changes how a person proves who they are when they sign in. It\ndoes not, by itself, decide who receives a membership, role or offboarding\naction. SCIM is different: it lets an identity directory own the lifecycle for\nthe people it manages. If your directory is the source of truth for this user,\nuse [SCIM provisioning](/user-administration/scim-provisioning) rather than\nmaking a competing manual change.\n\n## Check the result every time\n\nAfter a meaningful change, confirm the membership state and effective role in\nthe user-management screen. For a sensitive change, also review the audit\nrecord for the person affected, the administrator who made the change, the\norganization, and the outcome. Do not paste invitation links, reset material or\ncredentials into tickets or audit notes.`,\n },\n {\n managedPath: 'user-administration/invite-and-onboard-user.md',\n unitRef: 'technical-documentation:unit/invite-and-onboard-user',\n sourceRefs: [\n 'saas-technical-doc:engine-content/invite-and-onboard-user',\n ],\n 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.`,\n },\n {\n managedPath: 'user-administration/roles-and-permissions.md',\n unitRef: 'technical-documentation:unit/organization-roles',\n sourceRefs: [\n 'saas-technical-doc:engine-content/organization-roles',\n 'source:companion-projection:application-administration',\n 'source:companion-projection:organization-roles',\n 'source:consumer-fact:organization-membership-administration',\n ],\n 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.`,\n },\n {\n managedPath: 'user-administration/change-user-access.md',\n unitRef: 'technical-documentation:unit/change-user-access',\n sourceRefs: [\n 'saas-technical-doc:engine-content/change-user-access',\n ],\n 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.`,\n },\n {\n managedPath: 'user-administration/manage-organization-units.md',\n unitRef: 'technical-documentation:unit/manage-organization-units',\n sourceRefs: [\n 'saas-technical-doc:engine-content/manage-organization-units',\n 'source:companion-projection:application-administration',\n 'source:companion-projection:organization-unit-aware-resources',\n 'source:consumer-fact:organization-units',\n ],\n 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.`,\n },\n {\n managedPath: 'user-administration/design-organization-unit-hierarchy.md',\n unitRef: 'technical-documentation:unit/design-organization-unit-hierarchy',\n sourceRefs: ['saas-technical-doc:engine-content/design-organization-unit-hierarchy'],\n markdown: `# Design the organization-unit hierarchy\n\nBuild the smallest hierarchy that represents durable access boundaries. This\npage is for the administrator who understands how the organization is divided\nand can name which application information each part should control.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | An organization owner or administrator working with the business owners of each proposed access boundary |\n| **Where the design applies** | One organization and the application information that can be narrowed inside it |\n| **Before you begin** | Name the information or actions each unit must control, the owner of that boundary and the intended inheritance behavior |\n| **Successful result** | A small, explainable, cycle-free hierarchy exists before member assignments are added, with broad inheritance used only where it is intentional |\n\nUse the application’s organization-unit administration screen when one is\navailable. Otherwise, follow the organization-unit API operations linked from\nthis page. Do not edit the internal hierarchy path directly; create and move\nunits through the published operations.\n\n## Start from access, not the org chart\n\nAsk these questions for every proposed unit:\n\n- **What information or action will be narrowed by this unit?**\n- **Who decides who belongs here?**\n- **Should a role at this unit reach every child below it?**\n- **Will this structure remain understandable after the next reorganization?**\n\nIf the only answer is reporting, presentation or a temporary project label,\nkeep that information as ordinary business data instead of an authorization\nboundary.\n\n## Understand downward inheritance\n\n~~~mermaid\nflowchart TD\n accTitle: Organization-unit inheritance moves downward\n accDescr: A direct role at Sales reaches EMEA and France only when Sales passes access to descendants. A role at France never travels upward.\n manager[\"Sales manager\"] -->|\"Direct assignment\"| sales[\"Sales\"]\n sales --> emea[\"EMEA\"]\n emea --> france[\"France\"]\n manager -.->|\"Inherited when enabled\"| emea\n manager -.->|\"Inherited when enabled\"| france\n~~~\n\nInheritance moves from a unit to its descendants, never from a child to its\nparent. A root assignment with downward inheritance can reach the entire tree,\nso review it with the same care as a broad organization role.\n\n## Create the hierarchy\n\n1. Create only the top-level units that represent real access boundaries.\n2. Add a child when its access responsibility is meaningfully contained by the\n parent.\n3. Choose the descriptive type—company, division, department, team, subteam,\n project group, geographic, functional or custom. **The type itself grants no\n permission.**\n4. Give the unit a clear human name. Add a short code only when another process\n needs a stable sibling-level identifier.\n5. Enable downward inheritance only when parent responsibility should cover\n every current and future descendant.\n6. Review the tree before assigning a population.\n\nThe application maintains the internal hierarchy path when a unit is created or\nmoved. Do not expose or edit that path as a business identifier.\n\n## Review the design before assignment\n\n- Could one parent assignment unintentionally cover unrelated teams?\n- Will moving a branch later change inherited access for many people?\n- Can an administrator explain why every unit exists in access terms?\n- Is a directory department value expected to map to this exact unit?\n\nWhen the structure is ready, continue with [Assign organization-unit\naccess](/user-administration/assign-organization-unit-access).`,\n },\n {\n managedPath: 'user-administration/assign-organization-unit-access.md',\n unitRef: 'technical-documentation:unit/assign-organization-unit-access',\n sourceRefs: [\n 'saas-technical-doc:engine-content/assign-organization-unit-access',\n 'source:companion-projection:organization-unit-aware-resources',\n ],\n markdown: `# Assign organization-unit access\n\nAssign a person to a unit when they need access in one part of the organization\nwithout receiving the same authority everywhere. The person must already have\nan **Active** membership in the organization.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | An organization owner or administrator allowed to grant the selected role |\n| **Where the change applies** | One organization unit and, only when inheritance is enabled, its descendant units |\n| **Before you begin** | Confirm an active membership, the unit hierarchy, the role, inheritance and at least one application resource that is unit-aware |\n| **Successful result** | The person can perform the approved action in the intended unit while the same action remains unavailable in an unrelated unit |\n\nAn application may provide a dedicated organization-unit administration\nscreen. When it does not, use the organization-unit membership API operations\nlinked from this page. Do not assume that the **Members** screen exposes every\nunit operation: UI availability is an application choice, while the published\nAPI reference is the exact automation contract.\n\n> **A unit assignment is an additional, narrowed grant.** It does not replace\n> the person’s organization role and cannot reduce access already granted\n> organization-wide.\n\n~~~mermaid\nflowchart LR\n accTitle: Evaluate organization-wide and unit access\n accDescr: An organization-wide role can allow the operation first. Otherwise, the application checks a sufficient role on the record's unit or an inheriting ancestor.\n request[\"Person requests an operation\"] --> org{\"Organization-wide role allows it?\"}\n org -->|\"Yes\"| allow[\"Allow\"]\n org -->|\"No\"| narrowed{\"Resource is unit-aware?\"}\n narrowed -->|\"No\"| deny[\"Refuse\"]\n narrowed -->|\"Yes\"| unit{\"Sufficient direct or inherited unit role?\"}\n unit -->|\"Yes\"| allow\n unit -->|\"No\"| deny\n~~~\n\n## Make the assignment\n\n1. Confirm the intended person and organization membership.\n2. Select the unit where their responsibility begins.\n3. Choose one role for that member in that unit.\n4. Review the unit’s inheritance setting and every descendant it can cover.\n5. Save the assignment and inspect the resulting membership and unit.\n\nA member can belong to several units, but holds one role per unit. The\nadministrator can grant only roles inside their own organization-wide\nassignment ceiling. Holding a powerful role in one unit does not raise that\nceiling.\n\n## Prove both the access and its boundary\n\n{{APPLICATION_ORGANIZATION_UNIT_RESOURCES}}\n\nUse the person’s own account and choose a resource that the application\nexplicitly narrows by unit:\n\n- verify one approved action on a record in the assigned unit;\n- verify the same action on a descendant when inheritance is enabled;\n- verify that an unrelated sibling unit remains unavailable; and\n- verify that an authority-bearing area such as membership or API-key\n administration has not become available because of the unit role.\n\nSuccessful access alone is not enough evidence. The refused sibling action is\nwhat proves that the grant is narrow.\n\n### Why did the assignment not change anything?\n\nThe selected resource may not be unit-aware, the record may name another unit,\nthe assigned role may not satisfy the operation, the membership may not be\nactive, or inheritance may stop before the record’s unit. Check those facts\nbefore granting a broader organization role.`,\n },\n {\n managedPath: 'user-administration/operate-organization-units.md',\n unitRef: 'technical-documentation:unit/operate-organization-units',\n sourceRefs: ['saas-technical-doc:engine-content/operate-organization-units'],\n markdown: `# Operate the organization-unit hierarchy\n\nChanges to a live hierarchy can change inherited access for an entire branch.\nReview the affected people and unit-aware information before you move, archive,\nrestore or delete a unit.\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 the affected access boundaries |\n| **Where the change applies** | The selected unit, its descendants and the people whose inherited reach can change |\n| **Before you begin** | Export or inspect the branch, direct assignments, inherited assignments and representative unit-aware records |\n| **Successful result** | The hierarchy reaches the intended state, affected access is re-tested, unrelated units remain isolated and the audit record explains the change |\n\nUse the application’s organization-unit administration screen when it exposes\nthe required action. Otherwise, use the organization-unit API operations linked\nfrom this page; archive, restore, move and delete are distinct operations and\nmust not be simulated by editing fields.\n\n## Understand each operation\n\n| Action | What the application changes | What it does **not** do |\n| --- | --- | --- |\n| Move | Moves the unit and all descendants, then rewrites their maintained hierarchy paths | It does not preserve the former inherited reach |\n| Archive | Marks the selected unit archived | It does not revoke assignments, hide records or automatically archive descendants |\n| Restore | Returns an archived unit when its parent chain is available | It does not restore an archived ancestor first |\n| Delete | Removes an empty leaf unit | It does not silently detach child units or member assignments |\n\n> **Status is not revocation.** Archiving, suspending or deactivating a unit\n> records its operational state, but existing assignments and the records they\n> cover remain. Remove or change assignments when access must end.\n\n## Move a branch safely\n\n1. List the unit, all descendants and every direct member assignment.\n2. Compare inherited access at the old and proposed parent.\n3. Identify people who will gain or lose reach after the move.\n4. Move the branch only after the affected access owners approve the result.\n5. Re-test an approved and an unapproved unit-aware record.\n\nMoving a unit into itself or one of its descendants is refused because it would\ncreate a cycle.\n\n## Archive, restore or delete safely\n\n- Before archiving, decide whether assignments should remain for history or be\n removed to end access.\n- Restore the parent chain before restoring a child beneath an archived parent.\n- Before deletion, move or remove every child and remove every member assignment.\n Only an empty leaf can be deleted.\n- When SCIM owns the unit assignment, change the directory mapping rather than\n recreating a competing manual assignment.\n\nAfter every structural change, review the audit record and verify the practical\nresult with a representative member’s own account.`,\n },\n {\n managedPath: 'user-administration/suspend-or-remove-user.md',\n unitRef: 'technical-documentation:unit/suspend-or-remove-user',\n sourceRefs: [\n 'saas-technical-doc:engine-content/suspend-or-remove-user',\n ],\n 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.`,\n },\n {\n managedPath: 'user-administration/review-users-and-access.md',\n unitRef: 'technical-documentation:unit/review-users-and-access',\n sourceRefs: [\n 'saas-technical-doc:engine-content/review-users-and-access',\n ],\n 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.`,\n },\n {\n managedPath: 'user-administration/troubleshoot-user-access.md',\n unitRef: 'technical-documentation:unit/troubleshoot-user-access',\n sourceRefs: ['saas-technical-doc:engine-content/troubleshoot-user-access'],\n markdown: `# Troubleshoot user access\n\nStart with what the person experiences, then check identity, organization,\nmembership and role in that order. Do not grant a broader role merely because\nit makes the symptom disappear: that hides the cause and can create a second\naccess problem.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | The person experiencing the problem and an administrator who can inspect the relevant identity and membership state |\n| **Where the investigation applies** | The exact organization, resource and action where the symptom occurs |\n| **Before you begin** | Record the symptom, time, active organization and non-secret error details; never request a password, factor code or token |\n| **Successful result** | The failing decision is identified at the identity, organization, membership, role, unit or operation layer and corrected without broadening unrelated access |\n\n~~~mermaid\nflowchart TD\n accTitle: Diagnose user access in the order decisions are made\n accDescr: First prove the person can authenticate, then confirm the active organization and membership, then inspect organization and unit roles, and finally the exact requested action.\n symptom[\"Person reports an access problem\"] --> auth{\"Can they sign in?\"}\n auth -->|\"No\"| signin[\"Check sign-in method, factor and SSO\"]\n auth -->|\"Yes\"| org{\"Correct active organization?\"}\n org -->|\"No\"| switch[\"Select the intended organization\"]\n org -->|\"Yes\"| membership{\"Membership Active?\"}\n membership -->|\"No\"| lifecycle[\"Resolve invitation, suspension or directory state\"]\n membership -->|\"Yes\"| role{\"Role and unit assignment sufficient?\"}\n role -->|\"No\"| access[\"Review the intended least-privileged assignment\"]\n role -->|\"Yes\"| operation[\"Check the exact action and resource scope\"]\n~~~\n\n## Start from the symptom\n\n| The person says… | Check first | Safe next action |\n| --- | --- | --- |\n| “I cannot sign in” | Offered sign-in method, SSO routing, factor challenge and account state | Follow the sign-in or identity-provider recovery path; do not change a role yet |\n| “I did not receive the invitation” | Intended email, membership state and whether an earlier invitation exists | Correct or resend the invitation journey without creating a duplicate identity |\n| “I can sign in but see the wrong organization” | Active organization selection and membership in the intended organization | Switch to the intended organization; roles do not copy between memberships |\n| “I can open the application but cannot do this task” | Exact task, organization role, unit-aware resource and unit assignment | Compare the least-privileged role with the exact operation; test an approved and refused boundary |\n| “My access is paused” | Suspended or inactive membership, directory ownership and recovery condition | Reactivate only through the owning lifecycle path and preserve owner continuity |\n| “The directory change did not appear” | SCIM response, exact operation, mapping value and resulting resource state | Correct the directory/mapping or use a supported full reconciliation; do not create a competing manual state |\n\n## If the person cannot sign in\n\nConfirm the sign-in method actually offered for this person and organization.\nFor SSO, verify the identity-provider connection and the person’s directory\nassignment. A successful SSO assertion still needs a usable application user\nand organization membership. For a required second factor, use the published\nfactor-recovery journey; never ask the person to share a code or another\nperson’s session.\n\n## If sign-in works but access is wrong\n\n1. Confirm the active organization shown to the person.\n2. Confirm the membership is **Active** in that same organization.\n3. Compare organization roles with [Roles and\n permissions](/user-administration/roles-and-permissions).\n4. If the resource is unit-aware, inspect the record’s unit, the person’s direct\n assignment and any downward inheritance.\n5. Test with the person’s own account: one intended action and one nearby action\n that should remain refused.\n\nAn administrator’s successful test is not evidence that the person’s access is\ncorrect. Likewise, an API denial should be diagnosed from its credential and\noperation contract instead of repaired with a more powerful credential.\n\n## If a lifecycle change is refused\n\nCheck whether the action would leave the organization without a usable owner,\nwhether SCIM owns the membership, or whether the requested state transition is\nvalid from its current state. Establish another active owner before an owner\nreduction or removal. Make directory-owned changes in the directory and inspect\nthe resulting membership before retrying manually.\n\nWhen you escalate the issue, include the organization, affected membership\nstate, intended task, timestamp and non-secret error details. Remove tokens,\ncredentials and unnecessary personal data.`,\n },\n {\n managedPath: 'user-administration/scim-provisioning.md',\n unitRef: 'technical-documentation:unit/scim',\n sourceRefs: [\n 'saas-technical-doc:engine-content/scim',\n 'source:consumer-fact:organization-scim-provisioning',\n ],\n markdown: `# Provision users with SCIM\n\nSCIM lets an identity directory maintain a defined population of users and\norganization memberships. Choose it when your directory should own repeatable\njoiner, mover and leaver changes. The application supports **SCIM Users**, not\nSCIM Groups; a directory \\`department\\` can be mapped to one existing\norganization unit.\n\n> **SCIM provisions access; it does not sign people in.** Configure and prove\n> single sign-on separately. A directory-managed person needs both a correctly\n> provisioned membership and a working enterprise sign-in path.\n\n~~~mermaid\nflowchart LR\n accTitle: Adopt SCIM in four controlled stages\n accDescr: Configure the connection, map profile and unit data, validate with a small population, then operate and troubleshoot the live integration.\n configure[\"Configure lifecycle and credential\"] --> map[\"Map profile and unit data\"]\n map --> validate[\"Validate and roll out\"]\n validate --> operate[\"Operate and troubleshoot\"]\n~~~\n\n## How a directory change becomes application access\n\nProvisioning is not a single switch. A directory assignment passes through\nseveral independent decisions before a person can use the application:\n\n~~~mermaid\nsequenceDiagram\n accTitle: From directory assignment to usable application access\n accDescr: A directory administrator assigns a person, the identity provider sends a SCIM User request, the application validates the organization token and profile, maintains the identity and membership, optionally reconciles a mapped organization unit on supported operations, and responds. The person later signs in through a separate authentication journey and current membership and role determine access.\n actor Admin as Directory administrator\n participant Directory as Identity directory\n participant SCIM as Application SCIM service\n participant Access as Identity and membership\n participant Units as Organization units\n actor Person as Person\n Admin->>Directory: Assign person to the application\n Directory->>SCIM: Send SCIM User operation\n SCIM->>SCIM: Authenticate token and validate payload\n SCIM->>Access: Create or update identity and membership\n opt Department mapping on a supported operation\n SCIM->>Units: Reconcile mapped unit assignment\n end\n SCIM-->>Directory: Return SCIM result\n Person->>Access: Sign in through the configured method\n Access-->>Person: Evaluate current membership and role\n~~~\n\nThis journey separates six decisions that are often confused during a rollout:\n\n| Decision | Question the owners must answer |\n| --- | --- |\n| Provisioned population | Which directory assignment or group decides who is sent to the application? |\n| Identity matching | Which stable directory value identifies the same person after an email or name change? |\n| Initial access | Which non-administrative organization role should a newly provisioned person receive? |\n| Leaver behavior | What should happen to the application user and membership when the directory sends \\`active:false\\`? |\n| Unit authority | Should \\`department\\` merely describe the person, or authoritatively add and remove organization-unit access? |\n| Authentication | Which sign-in or SSO method will the person use after provisioning succeeds? |\n\n> **A successful SCIM response proves provisioning, not usable access.** Verify\n> the resulting membership, role and unit assignments, then ask the pilot person\n> to complete the separate sign-in journey.\n\n## Choose the stage you are working on\n\n| Your goal | Continue with |\n| --- | --- |\n| Understand the supported SCIM profile, payloads and operation behavior | [SCIM protocol and payload reference](/user-administration/scim-protocol-and-payloads) |\n| Decide lifecycle defaults and connect the directory | [Configure SCIM provisioning](/user-administration/scim-configure) |\n| Connect Microsoft Entra ID or a synchronized Active Directory population | [Connect Microsoft Entra ID](/user-administration/scim-microsoft-entra) |\n| Connect an Okta organization | [Connect Okta](/user-administration/scim-okta) |\n| Start from Active Directory Domain Services or another LDAP directory | [Connect an LDAP or Active Directory source](/user-administration/scim-ldap-and-active-directory) |\n| Map names, email and department-owned unit access | [Map SCIM profiles and organization units](/user-administration/scim-map-profile-and-units) |\n| Prove behavior with controlled users before broad enablement | [Validate and roll out SCIM](/user-administration/scim-validate-and-roll-out) |\n| Rotate credentials, investigate errors or recover a person | [Operate and troubleshoot SCIM](/user-administration/scim-operate-and-troubleshoot) |\n\n{{CONSUMER_FACT:source:consumer-fact:organization-scim-provisioning#markdown}}\n\n## Decide whether SCIM fits\n\nUse SCIM only when the directory will be the source of truth for the population,\nenterprise sign-in already works, and named owners can respond to provisioning\nfailures and credential changes. Keep people deliberately outside the directory\non the manual path. Do not let SCIM and an administrator compete to manage the\nsame membership or unit assignment.`,\n },\n {\n managedPath: 'user-administration/scim-protocol-and-payloads.md',\n unitRef: 'technical-documentation:unit/scim-protocol-and-payloads',\n sourceRefs: [\n 'saas-technical-doc:engine-content/scim-protocol-and-payloads',\n 'source:companion-projection:application-connection',\n 'source:consumer-fact:organization-scim-provisioning',\n ],\n 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\nThis is the complete base URL a provider needs. Everything below hangs off it:\n\n~~~text\n{{APPLICATION_CONNECTION_VALUE:scimBaseUrl}}\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.`,\n },\n {\n managedPath: 'user-administration/scim-configure.md',\n unitRef: 'technical-documentation:unit/scim-configure',\n sourceRefs: [\n 'saas-technical-doc:engine-content/scim-configure',\n 'source:companion-projection:application-connection',\n 'source:consumer-fact:organization-scim-provisioning',\n ],\n 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.`,\n },\n {\n managedPath: 'user-administration/scim-microsoft-entra.md',\n unitRef: 'technical-documentation:unit/scim-microsoft-entra',\n sourceRefs: ['saas-technical-doc:engine-content/scim-microsoft-entra'],\n markdown: `# Provision users from Microsoft Entra ID\n\nConnect one Microsoft Entra enterprise application to one application\norganization. Entra decides which assigned people should exist; SCIM creates or\nupdates their application identities and organization memberships. **This\nconnection provisions access—it does not configure how those people sign in.**\nConfigure and test single sign-on separately.\n\n~~~mermaid\nflowchart LR\n directory[\"Active Directory or another HR source\"] --> entra[\"Microsoft Entra ID\"]\n entra -->|\"SCIM 2.0 over HTTPS\"| endpoint[\"Application SCIM endpoint\"]\n endpoint --> identity[\"User profile\"]\n endpoint --> membership[\"Organization membership and role\"]\n endpoint -. \"department on supported operations\" .-> unit[\"Organization-unit assignments\"]\n~~~\n\nIf your source is on-premises Active Directory Domain Services, synchronize it\nto Entra first. The application does not accept LDAP traffic at its SCIM\nendpoint.\n\n## Before you configure Entra\n\n- Create a non-production organization or select a small pilot organization.\n- Verify that the pilot person can sign in by the organization’s intended\n authentication method.\n- Create the application’s SCIM provisioning configuration and a **dedicated\n token for this Entra connection**.\n- Choose a non-administrative default role. Do not provision broad access merely\n to make the first test pass.\n- Decide whether Entra’s \\`department\\` value should control organization-unit\n access. Leave unit mapping off until the operation behavior below is proven.\n\n## Create the enterprise application\n\n1. In the Microsoft Entra admin center, open **Enterprise applications** and\n create or select the application used for provisioning.\n2. Open **Provisioning**, choose an automatic provisioning mode, and start a new\n configuration.\n3. Set **Tenant URL** to the application’s public API origin followed by:\n\n ~~~text\n /api/v1/scim/v2\n ~~~\n\n4. Set **Secret Token** to the plaintext SCIM token returned by the application.\n It is a bearer credential; store it in Entra and your approved secret-recovery\n process, not in a ticket or documentation screenshot.\n5. Run **Test Connection**.\n\nEntra’s connection test queries a randomly generated, non-existent user. A\ncorrect empty result is HTTP 200 with a SCIM \\`ListResponse\\` and zero resources.\nThat proves URL, TLS, token and basic query compatibility. **It does not prove\nrole assignment, deactivation, department changes or sign-in.**\n\n## Configure the user mappings\n\nKeep the first mapping small and observable:\n\n| Entra source | SCIM target | Decision to verify |\n| --- | --- | --- |\n| \\`userPrincipalName\\` or a verified mail attribute | \\`userName\\` | Must be stable and unique for the person |\n| \\`mail\\` | \\`emails[type eq \"work\"].value\\` | Must resolve to an admitted organization domain when domain restrictions exist |\n| \\`givenName\\` | \\`name.givenName\\` | Check accents and empty values |\n| \\`surname\\` | \\`name.familyName\\` | Check the real payload, not the portal preview alone |\n| \\`displayName\\` | \\`displayName\\` | Decide which system owns later changes |\n| Account-enabled expression | \\`active\\` | Test disable and re-enable as separate access events |\n| \\`department\\` | Enterprise User \\`department\\` | Enable only if department is an access-control authority |\n\nThis application currently exposes **Users**, not SCIM **Groups**. Disable group\nobject provisioning and Push Groups-style expectations. Entra groups may still\nbe useful on the Entra side to decide who is assigned to the enterprise\napplication, but they are not imported as application groups.\n\n## Treat department-to-unit mapping as a controlled rollout\n\nThe application reconciles organization units on direct \\`POST /Users\\` and full\n\\`PUT /Users/{id}\\` operations. It does **not** currently reconcile units on\n\\`PATCH\\` or \\`Bulk\\`. Entra can use PATCH for attribute changes, so a successful\nprofile update does not prove that moving a person between departments removed\ntheir former unit access.\n\nBefore making department authoritative:\n\n1. Map one test department to one existing organization unit.\n2. Use **Provision on demand** for a pilot person and record the SCIM operation\n visible in the application/provider evidence.\n3. Change the person’s department.\n4. Confirm both the new assignment and removal of the old assignment in the\n application—not only a successful Entra job.\n5. If Entra sends PATCH, leave automatic unit reconciliation disabled until the\n application supports that operation or your integration deliberately sends a\n tested full replacement.\n\n## Roll out and operate\n\n- Start with **Sync only assigned users and groups** and assign a small pilot\n population. This scopes Entra’s source population; it does not add SCIM Group\n support to the application.\n- Verify in the application: user profile, membership status, organization role,\n unit assignments and sign-in.\n- Review Entra provisioning logs for the request and response associated with\n each pilot person. Preserve provider job identifiers, not bearer tokens.\n- Configure provisioning-failure notifications and review Microsoft’s\n accidental-deletion prevention before broad assignment.\n- Rotate a token as an immediate credential cutover: update Entra promptly and\n run the connection test again.\n\n## Microsoft documentation to keep with the runbook\n\n- Use Microsoft’s [provision users and groups with SCIM](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/use-scim-to-provision-users-and-groups)\n guide for current Entra portal controls, attribute mappings, test connection\n and provisioning behavior. The application-specific limits on this page\n still take precedence over generic provider capabilities.\n- Use [how Microsoft Entra provisioning works](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/how-provisioning-works)\n to understand the provider’s synchronization cycle and the path from a\n connected source such as Active Directory to an enterprise application.\n\nRecord the reviewed provider-documentation date in the production runbook;\nportal labels and provider behavior can change independently of the application.`,\n },\n {\n managedPath: 'user-administration/scim-okta.md',\n unitRef: 'technical-documentation:unit/scim-okta',\n sourceRefs: ['saas-technical-doc:engine-content/scim-okta'],\n markdown: `# Provision users from Okta\n\nUse an Okta SCIM 2.0 application to create, update and deactivate people in one\napplication organization. The Okta assignment determines who is provisioned;\nthe application’s SCIM configuration determines the role and lifecycle effects.\nSign-on configuration remains a separate SSO decision.\n\n~~~mermaid\nflowchart LR\n accTitle: Keep Okta assignment, provisioning and application access distinct\n accDescr: An Okta administrator assigns a person or population to the Okta application. Okta sends SCIM User operations to the application. The application maintains the user profile and organization membership, applies the configured default role, and optionally reconciles a mapped department on supported operations. The person signs in through a separately configured method.\n source[\"Okta user and assignment\"] --> provision[\"Okta provisioning connector\"]\n provision -->|\"SCIM User operations\"| endpoint[\"Application SCIM endpoint\"]\n endpoint --> profile[\"User profile\"]\n endpoint --> membership[\"Organization membership and default role\"]\n endpoint -. \"mapped department on supported operations\" .-> units[\"Organization-unit access\"]\n signin[\"Separate sign-in or SSO journey\"] --> membership\n~~~\n\nThe Okta assignment defines the population. It does not choose the\napplication role, import an Okta group as an application group, or prove that\nthe person can sign in. Verify those outcomes separately during the pilot.\n\n## Choose the correct Okta integration shape\n\nFor a private connection, create or use a **SCIM 2.0 Test App (Header Auth)** or\nanother Okta application whose provisioning connector lets you supply a SCIM\nbase URL and bearer token. If the application later has a reviewed Okta\nIntegration Network entry, follow that entry instead of duplicating it.\n\nThe application accepts SCIM **User** resources. It does not currently expose a\nSCIM Group resource, so do not enable Push Groups or depend on group-object\nimports. An Okta group can still control which users are assigned to the Okta\napplication.\n\n## Connect Okta\n\n1. In the Okta Admin Console, open the application’s **Provisioning** settings.\n2. Enable API integration and choose bearer/header authentication.\n3. Set the SCIM connector base URL to the application’s public API origin plus\n \\`/api/v1/scim/v2\\`.\n4. Paste a dedicated application-issued SCIM token into the API token field.\n5. Run **Test API Credentials**.\n\nThe credential test is a transport and authorization test. Complete a pilot\ncreate, update and deactivate before treating the connection as ready.\n\n## Configure provisioning actions\n\nEnable only the actions you are prepared to verify:\n\n| Okta **To App** action | Application effect to test |\n| --- | --- |\n| Create Users | Creates or links the user, then creates the organization membership with the configured default role |\n| Update User Attributes | Updates maintained profile values; inspect whether Okta used PUT or PATCH |\n| Deactivate Users | Normally sends \\`active:false\\`; verify the application user and organization membership consequences |\n| Sync Password | **Keep disabled.** The SCIM service does not accept password changes |\n\nUse a stable, unique Okta attribute for \\`userName\\`. Map the work email, given\nname, family name and display name explicitly. When verified-domain restrictions\nexist, ensure the resolved work email is admitted before the pilot.\n\n### Department and organization units\n\nMap Okta’s department to the SCIM Enterprise User extension only when it is\nauthoritative enough to change access. Then map exact department values to\nexisting application organization units.\n\n> **Operation limitation:** organization-unit reconciliation currently runs for\n> direct user creation and full replacement. It does not run for PATCH or Bulk.\n> Capture the operation Okta sends for a department change and prove that the\n> old unit assignment is removed before production rollout.\n\n## Prove one complete lifecycle\n\n1. Assign one pilot user to the Okta application.\n2. Confirm the person appears in the intended application organization with the\n approved role—not an administrator role.\n3. Change one mapped profile value and confirm it in the application.\n4. If unit mapping is enabled, move the pilot between two mapped departments and\n confirm both addition and removal.\n5. Unassign or deactivate the pilot. Confirm the user and membership state in\n the application and verify the effect on any other organization membership.\n6. Reassign the pilot. Confirm that the organization membership is usable again;\n a globally active user alone is not sufficient proof.\n\nUse Okta’s **System Log** and provisioning task details to correlate failures.\nRecord time, Okta user/application identifiers, SCIM operation, HTTP status,\nredacted SCIM error and resulting application state. Never record the API token.\n\n## Okta documentation to keep with the runbook\n\n- Use Okta’s [connect a private SCIM integration](https://developer.okta.com/docs/guides/scim-provisioning-integration-connect/main/)\n guide for current Admin Console fields and connector setup.\n- Use the [Okta SCIM protocol reference](https://developer.okta.com/docs/api/openapi/okta-scim/guides)\n when diagnosing the operation, filter, payload or response Okta expects.\n- Use [Understanding SCIM](https://developer.okta.com/docs/concepts/scim/)\n to align directory and application owners on assignment, provisioning and\n deprovisioning responsibilities.\n\nKeep the application profile on this page beside those provider references:\nOkta’s support for a feature does not mean this application exposes it.`,\n },\n {\n managedPath: 'user-administration/scim-ldap-and-active-directory.md',\n unitRef: 'technical-documentation:unit/scim-ldap-and-active-directory',\n sourceRefs: ['saas-technical-doc:engine-content/scim-ldap-and-active-directory'],\n markdown: `# Provision from LDAP or Active Directory\n\nLDAP and SCIM solve different parts of directory integration. LDAP is a\ndirectory access protocol; this application exposes an HTTPS SCIM 2.0 service.\n**Do not send LDAP requests to the SCIM URL and do not expose an internal LDAP\nserver to the application.** Place a provisioning service or controlled bridge\nbetween the source directory and SCIM.\n\n## Choose an architecture\n\n~~~mermaid\nflowchart LR\n subgraph source[\"Directory source\"]\n ad[\"Active Directory Domain Services\"]\n ldap[\"LDAP directory\"]\n end\n ad --> entra[\"Microsoft Entra synchronization and provisioning\"]\n ldap --> bridge[\"Managed provisioning agent or owned bridge\"]\n entra -->|\"HTTPS + SCIM 2.0\"| app[\"Application SCIM Users service\"]\n bridge -->|\"HTTPS + SCIM 2.0\"| app\n~~~\n\n| Source situation | Practical route |\n| --- | --- |\n| Active Directory identities already synchronized to Microsoft Entra ID | Configure Entra enterprise-application provisioning and let Entra emit SCIM |\n| LDAP identities governed through Okta | Use the supported Okta directory/agent path, then configure Okta’s application provisioning connector |\n| Another LDAP directory with a supported identity-governance product | Use that product’s SCIM connector after validating this application’s implemented profile |\n| No provider can emit the required SCIM profile | Build and operate a narrow LDAP-to-SCIM bridge with explicit ownership, tests and monitoring |\n\nThe last option is software you own. It should not be treated as a configuration\nscript: it becomes an identity lifecycle and access-control component.\n\n## Define the attribute transformation\n\nRead the source directory using its documented schema, then emit a standards-\ncompliant SCIM User. A common starting point is:\n\n| LDAP / Active Directory value | SCIM value | Required decision |\n| --- | --- | --- |\n| \\`userPrincipalName\\` or approved login attribute | \\`userName\\` | Stable uniqueness and rename policy |\n| \\`mail\\` | \\`emails[type eq \"work\"].value\\` | Missing email and verified-domain policy |\n| \\`givenName\\` | \\`name.givenName\\` | Empty and internationalized values |\n| \\`sn\\` | \\`name.familyName\\` | Empty-value behavior |\n| \\`displayName\\` | \\`displayName\\` | Which system owns later edits |\n| \\`department\\` | Enterprise User \\`department\\` | Whether it is authoritative for unit access |\n| Disabled-account state | \\`active:false\\` | Global user and membership deactivation consequence |\n\nThese are mapping decisions, not guaranteed attributes in every LDAP schema.\nInspect representative entries and document the source object classes,\nattribute ownership and null behavior.\n\n### Example SCIM document emitted by a bridge\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\": \"4fd9cc8d-7f42-4ab4-9036-07c94b2ac663\",\n \"userName\": \"alex.morgan@example.com\",\n \"active\": true,\n \"name\": {\n \"givenName\": \"Alex\",\n \"familyName\": \"Morgan\"\n },\n \"emails\": [\n { \"type\": \"work\", \"primary\": true, \"value\": \"alex.morgan@example.com\" }\n ],\n \"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User\": {\n \"department\": \"Engineering\"\n }\n}\n~~~\n\n## Requirements for an owned bridge\n\nA production bridge needs all of the following:\n\n- TLS validation for LDAP and HTTPS, and secrets held in an approved vault;\n- a durable relationship between source identifiers, SCIM \\`externalId\\` and the\n application’s returned SCIM resource identifier;\n- deterministic create-versus-update matching and a documented rename policy;\n- bounded pagination, checkpoints, retry with backoff and idempotent replay;\n- explicit handling for disable, delete, restore and a person missing from a\n source query;\n- redacted operational evidence linking one source change to one SCIM response;\n- reconciliation that detects drift rather than repeatedly overwriting it;\n- a tested response to rate limiting, token rotation and partial batch failure.\n\nDo not use Bulk for a first implementation merely for speed. The application\nsupports a bounded Bulk request, but Bulk currently does not perform\norganization-unit reconciliation. Start with observable individual operations.\n\n## Validate before production\n\nRun a positive and negative lifecycle: create an admitted user, reject a user\nfrom a disallowed domain when restrictions exist, update the profile, change a\ndepartment, disable the source account and restore it. At every step compare\nthe directory state, emitted SCIM document, HTTP result, application user,\nmembership, role and unit assignments.\n\n## Standards and provider documentation\n\n- [RFC 4511](https://www.rfc-editor.org/rfc/rfc4511.html) defines LDAP’s\n protocol. It explains the source-side boundary; it does not make an LDAP\n directory a SCIM provider.\n- [RFC 7643](https://www.rfc-editor.org/rfc/rfc7643.html) and\n [RFC 7644](https://www.rfc-editor.org/rfc/rfc7644.html) define the SCIM\n resource and protocol boundaries the bridge must emit.\n- Microsoft documents the path from connected systems to SCIM in\n [How application provisioning works](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/how-provisioning-works).\n- For an Okta-governed directory, compare the bridge design with Okta’s\n [private SCIM integration guide](https://developer.okta.com/docs/guides/scim-provisioning-integration-connect/main/)\n and [SCIM protocol reference](https://developer.okta.com/docs/api/openapi/okta-scim/guides).\n\nThese references define the systems on either side of the bridge. The bridge’s\nmatching, checkpoint, retry and reconciliation behavior remains an operated\ncomponent your organization must specify and test.`,\n },\n {\n managedPath: 'user-administration/scim-map-profile-and-units.md',\n unitRef: 'technical-documentation:unit/scim-map-profile-and-units',\n sourceRefs: ['saas-technical-doc:engine-content/scim-map-profile-and-units'],\n markdown: `# Map SCIM profiles and organization units\n\nMap the directory’s actual payload to the profile values the application needs.\nThen, only when department data should control access, map exact department\nvalues to existing organization units.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | The organization administrator and directory engineer who know the real SCIM payload |\n| **Where the mapping applies** | One organization’s SCIM provisioning configuration |\n| **Before you begin** | Capture representative non-production payloads, create every target unit and decide whether department data should be authoritative for unit assignments |\n| **Successful result** | Each required profile field resolves predictably, each approved department maps exactly once, and unmapped or malformed values have a tested outcome |\n\nOpen **Settings → User provisioning → Provisioning** for the organization, then\nedit the attribute and organization-unit mappings. Use the linked SCIM\nconfiguration API reference when the mapping is maintained by automation.\n\n## Map profile values\n\n| Application value | Built-in SCIM path |\n| --- | --- |\n| Email | \\`emails[0].value\\` |\n| Given name | \\`name.givenName\\` |\n| Family name | \\`name.familyName\\` |\n| Display name | \\`displayName\\` |\n\nCustom expressions may use dotted fields, an array index or an \\`eq\\` filter:\n\n- \\`name.givenName\\`\n- \\`emails[primary eq true].value\\`\n- \\`emails[type eq \"work\"].value\\`\n\n> **Test paths against a real directory payload.** A malformed or unmatched\n> expression does not necessarily reject the request. It can produce no value;\n> email may fall back to \\`userName\\`, the primary email or the first email,\n> while another profile field remains empty.\n\n## Understand verified email domains\n\nSCIM mirrors verified domains from the organization’s SSO configuration; it\ndoes not keep another list. A non-empty list restricts admitted email domains.\nAn empty or unavailable list leaves provisioning unrestricted by email domain.\nIf your policy requires a restriction, stop until at least one verified domain\nis visible and a deliberately invalid domain is refused.\n\n## Map a department to a unit\n\nEach mapping binds one exact directory value to one existing unit:\n\n~~~text\n\"Sales\" -> existing Sales organization unit\n~~~\n\nMatching trims surrounding whitespace but is case-sensitive. \\`Sales\\` and\n\\`sales\\` are different. The application does not search by unit name or code,\ndoes not use fuzzy matching and never creates the missing unit.\n\n~~~mermaid\nflowchart LR\n accTitle: Reconcile a directory department to unit access\n accDescr: An exact department value selects one configured unit. With a default unit role, a supported full reconciliation replaces the person's directory-managed unit assignments.\n payload[\"SCIM User department\"] --> exact{\"Exact configured value?\"}\n exact -->|\"Yes\"| unit[\"Existing organization unit\"]\n unit --> role[\"Configured default unit role\"]\n role --> replace[\"Replace desired unit assignments\"]\n exact -->|\"No or blank\"| remove[\"No mapped desired assignment\"]\n~~~\n\nReconciliation becomes active only with at least one explicit mapping and a\ndefault unit role. On supported direct user creation and full replacement, the\ndirectory becomes authoritative: a changed, blank or unmapped department can\nremove former assignments, including manual ones. **PATCH and Bulk do not\ncurrently perform this reconciliation.** Prove the exact operation used by\nyour identity provider.`,\n },\n {\n managedPath: 'user-administration/scim-validate-and-roll-out.md',\n unitRef: 'technical-documentation:unit/scim-validate-and-roll-out',\n sourceRefs: ['saas-technical-doc:engine-content/scim-validate-and-roll-out'],\n markdown: `# Validate and roll out SCIM\n\nDo not enable a full directory population after a successful connection check.\nUse a small controlled group and inspect the resulting user, membership, role,\nunit assignment and sign-in behavior after every change.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | The identity-directory owner, an organization administrator and the owner of the pilot population |\n| **Where validation applies** | One non-production or tightly controlled organization cohort |\n| **Before you begin** | Define expected identities, roles, units and states for every test case, plus the stop and rollback decision |\n| **Successful result** | Real SCIM operations match the expected application state for creation, update, movement, deactivation and recovery before the next cohort is enabled |\n\n> **The current connection-test and provisioning-statistics actions are not\n> readiness evidence.** Prove the integration with real controlled SCIM\n> operations and authoritative application state.\n\n## Run the validation matrix\n\n1. **Create a new person.** Verify the user state, organization membership,\n organization role and enterprise sign-in path.\n2. **Send an existing email.** Confirm that it links to the intended identity\n and does not create a duplicate.\n3. **Change each mapped profile value.** Inspect the destination after the\n directory operation.\n4. **Exercise email verification.** When automatic verification is off, prove\n the pending-verification and resend journey.\n5. **Move a department.** Use a direct full replacement, then confirm the former\n unit assignment was removed.\n6. **Send blank, unmapped and wrong-case departments.** Verify the exact result\n before making mapping authoritative.\n7. **Deactivate a multi-organization person.** Inspect both the global user and\n every affected membership.\n8. **Recover the person.** Confirm that the user and intended membership are\n both **Active** and that enterprise sign-in succeeds.\n\n## Roll out in stages\n\n~~~mermaid\nflowchart LR\n accTitle: Expand SCIM only after each cohort is verified\n accDescr: Begin with controlled identities, then a representative pilot, then broader cohorts. Stop and reconcile differences before proceeding.\n controlled[\"Controlled identities\"] --> pilot[\"Representative pilot\"]\n pilot --> cohort[\"First production cohort\"]\n cohort --> broad[\"Broader population\"]\n controlled -.-> stop[\"Stop on unexplained difference\"]\n pilot -.-> stop\n cohort -.-> stop\n~~~\n\nFor each stage, name the expected count and membership states, reconcile the\nresult, document exceptions and retain a rollback decision. Do not silently\nrepair directory-owned people in the application; fix the authoritative input\nor explicitly move the person to manual ownership.`,\n },\n {\n managedPath: 'user-administration/scim-operate-and-troubleshoot.md',\n unitRef: 'technical-documentation:unit/scim-operate-and-troubleshoot',\n sourceRefs: ['saas-technical-doc:engine-content/scim-operate-and-troubleshoot'],\n markdown: `# Operate and troubleshoot SCIM\n\nOperate SCIM as a security-sensitive directory connection: protect its token,\nreconcile outcomes from authoritative state and investigate errors before\nretrying. A request reaching the service is not proof that provisioning\nsucceeded.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | The directory operator and an organization administrator able to inspect provisioning state |\n| **Where the operation applies** | One organization, directory environment and dedicated SCIM credential |\n| **Before you begin** | Record the affected user, operation, time and redacted response; identify the authoritative owner before making a correction |\n| **Successful result** | The credential or provisioning failure is corrected, one controlled operation succeeds, and the final user, membership, role and unit state is verified |\n\nUse **Settings → User provisioning → Tokens** for token lifecycle work and\n**Provisioning** for configuration and mapping checks. The linked API references\nremain authoritative for exact automation operations and responses.\n\n## Replace or revoke a token\n\nAn in-place rotation is an **immediate cutover**. The previous secret stops\nworking with no overlap. For a planned replacement without interruption:\n\n1. create a second dedicated token;\n2. install it in the identity provider;\n3. prove it with a controlled user operation;\n4. revoke the former token; and\n5. retain only the non-secret metadata needed for review.\n\nRevocation keeps the token record and marks it inactive. A last-used time proves\nthat authenticated traffic reached the service; it does not prove that the user\nchange completed successfully.\n\n## Start from the symptom\n\n| Symptom | First checks |\n| --- | --- |\n| **401** | Token is exact, active, unexpired and sent as a bearer credential |\n| **403** | The organization type permits SCIM and the request belongs to the intended organization |\n| **409** | An existing identity or membership conflicts; inspect it instead of creating a duplicate |\n| **429** | Follow retry information and reduce concurrency |\n| Profile value is missing | Test the exact mapping expression against the real directory payload |\n| Unit did not change | Confirm exact department value and case, explicit mapping, existing unit, default role and a supported direct create/full replacement operation |\n| Person remains unable to sign in | Check enterprise sign-in, global user state and organization membership state separately |\n\n## Recover safely\n\n- Read the SCIM error returned to the identity provider before retrying.\n- Inspect the user, membership, role and unit assignments in the application.\n- Correct the directory or mapping when it owns the person; do not create a\n manual competing state.\n- For deactivation recovery, confirm both the global user and intended\n membership are **Active**.\n- Re-run one controlled operation and inspect its final resource state.\n\nRedact bearer tokens and unnecessary personal data before sharing payloads or\nerrors with support.`,\n },\n {\n managedPath: 'security-and-audit/audit-trail-and-siem.md',\n unitRef: 'technical-documentation:unit/audit-and-siem',\n sourceRefs: ['saas-technical-doc:engine-content/audit-and-siem'],\n markdown: `# Security and audit\n\nThe audit trail answers **who or what acted, what changed, where it happened,\nwhen it happened and whether it succeeded**. Use it to investigate access and\nadministrative activity. Use SIEM export when a security team needs selected\norganization events delivered to its own monitoring system.\n\nThese are two related but separate paths. The application writes the\nauthoritative audit record first. SIEM delivery is a filtered outbound copy. A\nSIEM outage therefore does not erase the application's stored event, and a\nsuccessful SIEM delivery does not replace the source record.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Know the organization and environment, the question being investigated, the authorized reviewer and the smallest useful time range | A stored event or bounded absence is reconciled with current application state, any SIEM delivery issue is treated separately, and controlled evidence has an owner and retention rule |\n\n~~~mermaid\nflowchart LR\n accTitle: Separate authoritative audit creation from SIEM delivery\n accDescr: A protected action creates an immutable application audit record. The organization filter may select that event for formatting and delivery to the SIEM. Failed delivery moves to the dead-letter queue while the original record remains available for investigation.\n action[\"Protected action or access decision\"] --> record[\"Immutable application audit record\"]\n record --> investigate[\"In-product investigation and bounded JSON export\"]\n record --> filter{\"Organization SIEM filter selects event?\"}\n filter -->|No| retained[\"Record remains in audit trail\"]\n filter -->|Yes| deliver[\"Format and deliver to SIEM\"]\n deliver -->|Success| siem[\"Organization SIEM\"]\n deliver -->|Failure| dlq[\"SIEM delivery queue for recovery\"]\n~~~\n\n## Understand what the trail proves\n\nAn audit row records that the application observed a particular action or\ndecision at a time. Its event identifier follows that event across retained and\nexported copies; its correlation identifier links activity from the same\nrequest or job. Actor, source, organization, outcome and event-specific data\nexplain the recorded context.\n\nThe trail does **not** automatically prove that:\n\n- the resource still has the same state now;\n- a declared event name is actually emitted by every operation;\n- the SIEM received its copy;\n- a broad export contains every matching row; or\n- a successful administrative action was low risk.\n\nReconcile material findings with the current authoritative resource. Treat a\nmissing expected row as a question about scope, filters, time and producer\ncoverage—not immediate proof that no action happened.\n\n## Keep actor and authority visible\n\n| Actor description | Meaning for investigation |\n| --- | --- |\n| Named person | The action is attributed to that person; verify the membership and role that applied at the time |\n| Machine | An API key or OAuth client acted; identify the credential record and owning workload |\n| System | A scheduled, internal or lifecycle process acted by design |\n| Unattributed | A principal was expected but could not be resolved; treat this as an anomaly to investigate |\n\nThe actor can differ from the person or resource affected by the action. Keep\nboth in the investigation so an administrator changing another person's access\nis not misread as self-service.\n\n## Choose the task you need\n\n- [Investigate an audit event](/security-and-audit/investigate-event) from a\n bounded symptom, time and organization scope.\n- [Review access and privileged changes](/security-and-audit/review-access-changes)\n without relying on declared-but-unemitted event names.\n- [Export a bounded audit window](/security-and-audit/export-audit-records) as\n JSON for an approved investigation.\n- [Configure organization SIEM export](/security-and-audit/configure-siem) with\n the appropriate format, authentication and event filter.\n- [Operate and troubleshoot SIEM delivery](/security-and-audit/operate-siem)\n from retries and dead-letter state.\n- [Protect and retain audit evidence](/security-and-audit/protect-evidence)\n without turning a diagnostic copy into an uncontrolled data store.\n- [Respond to a leaked credential](/security-and-audit/respond-to-leaked-credential)\n in the order an incident requires: contain, then assess, then recover.\n\nClose each task with the question, organization/environment, filters and time\nboundary, event and correlation identifiers, current-state comparison, reviewer\ndecision and owned follow-up. Never place credentials, complete tokens or an\nunrestricted evidence export in an ordinary support ticket.`,\n },\n {\n managedPath: 'security-and-audit/investigate-event.md',\n unitRef: 'technical-documentation:unit/investigate-audit-event',\n sourceRefs: [\n 'saas-technical-doc:engine-content/investigate-audit-event',\n 'source:consumer-fact:organization-audit-trail',\n ],\n 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.`,\n },\n {\n managedPath: 'security-and-audit/review-access-changes.md',\n unitRef: 'technical-documentation:unit/review-privileged-and-access-changes',\n sourceRefs: ['saas-technical-doc:engine-content/review-privileged-and-access-changes'],\n markdown: `# Review access and privileged changes\n\nAn access review should connect the authority that existed, the action that was\nattempted and the authority that exists now. Searching only for a person's name\ncan miss machine access, system-initiated lifecycle work and changes made to the\nperson by another administrator.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Define the organization, review period, people and machine identities in scope, the reviewer and the approved source of current access | Every material grant, refusal and removal is reconciled with current membership and role state, exceptions have owners, and the review decision retains traceable evidence |\n\n## Ask a reviewable question\n\n“Review all access” is too broad to prove. Start with one question whose answer\nchanges an access decision, for example:\n\n- Who gained or lost an organization-wide role during this period?\n- Which people were invited, suspended, reactivated or removed?\n- Which organization-unit assignments changed for a sensitive resource?\n- Which API key or OAuth client roles changed, and who approved the change?\n- Which refused privileged operations indicate repeated misuse or a broken\n administrative process?\n\nRecord the organization, start and end time, target identities and event\nfamilies before searching. Use a bounded export only after the search is narrow\nenough to explain; a large download does not make the review more complete.\n\n## Review the important event families\n\n- **Authentication:** successful and failed sign-in, lockout, SSO enforcement,\n credential and multifactor changes.\n- **Authorization:** refused operations, application-role changes,\n organization-role changes and organization-unit grants or revocations.\n- **User lifecycle:** invitation or membership operations, suspension,\n reactivation and removal evidence.\n- **Organization security configuration:** SSO, SCIM, SIEM and authentication\n policy changes.\n- **Machine activity:** machine authentication and the protected operation a\n machine credential exercised through an external surface.\n\nAdministrative success is not automatically low importance. Role changes and\nother privilege-bearing operations are classified to remain visible even when\nthey were authorized.\n\nDeclared event names are not evidence on their own. Review stored records that\nwere actually emitted, and use generic protected-operation evidence when a\ndedicated lifecycle name is not produced. Absence of one expected label does\nnot prove the underlying change was unaudited.\n\n~~~mermaid\nflowchart TD\n accTitle: Review a privilege change from decision to current state\n accDescr: The reviewer identifies the target identity and scope, finds the role or access operation, verifies actor and outcome, follows correlated events, and compares the recorded change with current membership and role state.\n target[\"Identity and organization under review\"] --> event[\"Find grant, revoke, refusal or lifecycle event\"]\n event --> actor[\"Verify actor, source and outcome\"]\n actor --> correlation[\"Follow related correlation events\"]\n correlation --> current[\"Compare with current membership and role state\"]\n current --> decision{\"Access still appropriate?\"}\n decision -->|Yes| evidence[\"Record review decision\"]\n decision -->|No| remediate[\"Use the normal access-change workflow\"]\n~~~\n\nUse the user-administration procedures to remediate access. Never edit audit\nrows to make current state appear consistent: audit records have no update or\ndelete operation.\n\n## Close the review against current state\n\n| Finding | Verify now | Close with |\n| --- | --- | --- |\n| Intended grant | Membership is active and the current role still matches the approved work | Reviewer, approval reference and next review date |\n| Excess or unexplained access | Current membership, organization-unit assignment, API key or OAuth client still carries it | Normal access-removal workflow plus the resulting audit evidence |\n| Refused privileged action | Actor, operation, reason and correlated attempts | Explained benign cause or an owned security investigation |\n| Access removed in the audit trail | Current state no longer authorizes the identity and no sibling credential preserves the same access | Verification time and the identity or credential checked |\n| Trail and current state disagree | Scope, time boundary, propagation and whether a later event superseded the first | Reconciliation decision; never a rewritten audit row |\n\nFinish by recording what was reviewed, the filters used, the current-state\nchecks performed, unresolved exceptions and who owns each follow-up. Exclude\ncredentials and unrestricted personal data from the review record.`,\n },\n {\n managedPath: 'security-and-audit/export-audit-records.md',\n unitRef: 'technical-documentation:unit/export-audit-records',\n sourceRefs: ['saas-technical-doc:engine-content/export-audit-records'],\n markdown: `# Export a bounded audit window\n\nUse the audit export operation when an organization administrator needs a small,\nreviewable set of source records for an investigation. This is a synchronous\nJSON response, not an archive job, CSV download or continuing SIEM feed.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Have an approved investigation purpose, the intended organization, a narrow time window and a protected destination | The response is small enough to review, its scope is verified and the retained copy has an owner and deletion rule |\n\n## Choose the right evidence path\n\n| Need | Use | Why |\n| --- | --- | --- |\n| Inspect events interactively | Audit search or list | You can refine filters before creating another copy |\n| Collect up to 100 matching source records | Bounded audit export | It returns one synchronous JSON evidence window with a matching count |\n| Deliver selected future events continuously | SIEM export | The receiver gets filtered events as they occur, with delivery and recovery state |\n| Preserve evidence under a long-term retention programme | Governed archival process | Retention, access, integrity and deletion require controls beyond a one-off download |\n\nDo not use a broader mechanism merely because it is available. A one-off\ninvestigation normally starts with search, then exports only the records needed\nfor review.\n\n## Define the window before exporting\n\nFilter by the narrowest useful combination of event type, category, severity,\nuser, organization, application and creation-time range. An authenticated\norganization scope takes precedence over a caller-supplied organization filter.\nThe response contains at most **100 records** and reports the total matching\ncount so you can tell when the requested investigation exceeds one bounded\nwindow.\n\nAsk these questions before sending the request:\n\n- Which event, person, credential, resource or correlation starts the review?\n- Which organization and environment own the evidence?\n- What is the smallest time range that includes the suspected action and its\n immediate consequences?\n- Which filters can exclude unrelated people or business activity?\n- Who is authorized to receive the exported copy, and when should it be\n deleted?\n\n~~~mermaid\nflowchart TD\n accTitle: Export a small, controlled audit evidence window\n accDescr: The investigator defines a purpose and authorized organization, narrows filters and time, requests up to one hundred JSON records, compares the returned count with the matching total, and either protects the result or narrows the request again.\n question[\"State the investigation question\"] --> scope[\"Confirm organization and environment\"]\n scope --> filter[\"Choose narrow event, actor and time filters\"]\n filter --> request[\"Request up to 100 JSON records\"]\n request --> count{\"totalCount fits this window?\"}\n count -->|Yes| verify[\"Verify records and preserve identifiers\"]\n count -->|No| narrow[\"Narrow the filter or time window\"]\n narrow --> request\n verify --> protect[\"Store, approve and delete under policy\"]\n~~~\n\nThe count is part of the evidence. If **totalCount** is greater than the returned\nrecords, the response is incomplete for that filter. Narrow the investigation;\ndo not describe the first 100 records as the complete result.\n\n## Export and verify the response\n\n1. Confirm the caller is authorized to export audit evidence for the intended\n scope. The exact API-reference operation defines the admitted roles.\n2. Submit the narrow filters and a **maxRecords** value from 1 through 100.\n3. Confirm the response format is **json** and retain **totalCount** with the\n records.\n4. Verify the organization, application and creation-time range on the returned\n events before using them as evidence.\n5. Preserve event IDs and correlation IDs byte-for-byte so another reviewer can\n trace the same activity.\n6. Compare material changes or outcomes with the application's current\n authoritative state. An audit row proves what was recorded; it does not prove\n that the current resource still has that state.\n\n## Handle the result safely\n\nTreat the exported JSON as a new controlled copy of security and potentially\npersonal information:\n\n- record who approved it, who created it, the purpose, filters, time and\n **totalCount**;\n- store it only in an approved location with named access and a deletion date;\n- protect integrity when it is used as formal evidence;\n- redact unnecessary personal data before attaching a subset to a ticket;\n- never place the export in source control, ordinary chat or an unrestricted\n shared folder.\n\nThe export does not remove records from the application. If you need continuous\ndelivery, configure SIEM export. If you need long-term archival, use the\napplication's governed archival policy rather than repeatedly downloading\noverlapping JSON windows.\n\n## If the export is empty or incomplete\n\n| Result | Check next |\n| --- | --- |\n| No records | Organization/environment, time zone, time range and whether the event was actually emitted |\n| Fewer records than expected | Event category/type and actor filters, then compare **totalCount** |\n| Exactly 100 records with a larger **totalCount** | Narrow the time range or other filters; the response is a bounded window, not pagination |\n| A forbidden response | Caller authority and the exact operation contract; do not switch to a broader credential without approval |\n| A timeout or lost response | Read or repeat a narrow, idempotent export only after confirming no uncontrolled copy was stored by the caller |`,\n },\n {\n managedPath: 'security-and-audit/configure-siem.md',\n unitRef: 'technical-documentation:unit/configure-siem-export',\n sourceRefs: [\n 'saas-technical-doc:engine-content/configure-siem-export',\n 'source:consumer-fact:organization-siem-export',\n ],\n markdown: `# Configure organization SIEM export\n\nSIEM export sends selected organization audit events to one webhook destination.\nCreate a destination dedicated to the organization and environment, then choose\nthe authentication, wire format and filters your receiver can actually verify.\n\n| Before you begin | Successful result |\n| --- | --- |\n| The organization security owner and SIEM owner agree on destination, TLS, authentication, event scope, format, volume, retention and a controlled test event | One organization/environment sends only the approved event set, the receiver validates and correlates it, failures are recoverable, and the destination secret remains protected |\n\n~~~mermaid\nflowchart TD\n accTitle: Configure a bounded organization SIEM export\n accDescr: The organization and SIEM owners prepare one receiver, choose authentication and a format, select a narrow category and severity filter, keep export disabled while validating configuration, enable it for one controlled event, compare the received copy with the source audit row, then expand deliberately.\n owners[\"Agree owners, organization and receiver\"] --> receiver[\"Prepare TLS, authentication and acknowledgement\"]\n receiver --> format[\"Choose one receiver-supported format\"]\n format --> filter[\"Select minimum event set and severity\"]\n filter --> disabled[\"Save while export remains disabled\"]\n disabled --> enable[\"Enable and perform one controlled event\"]\n enable --> compare[\"Compare event ID, scope, time, actor and outcome\"]\n compare --> expand[\"Expand only after volume and recovery checks\"]\n~~~\n\nSIEM export is an organization-routed copy of source audit events. Configure one\nreceiver per intended organization/environment boundary; do not use a shared\ndestination when its access and retention rules cannot preserve that separation.\n\n## Follow one event from source record to searchable copy\n\n~~~mermaid\nsequenceDiagram\n accTitle: From application audit record to searchable SIEM copy\n accDescr: The application records an audit event, applies the organization export filter, formats one outbound event, authenticates an HTTPS request, and sends it to the receiver. A successful HTTP response acknowledges the configured delivery boundary; the SIEM then parses and indexes the copy. Operators prove completion by searching for the source event identifier. Failed delivery follows retry and dead-letter recovery without removing the source audit record.\n participant Source as Source audit trail\n participant Export as Organization exporter\n participant Receiver as Receiver or relay\n participant SIEM as SIEM index\n actor Operator as Security operator\n Source->>Export: Eligible audit event\n Export->>Export: Apply filter and format one event\n Export->>Receiver: Authenticated HTTPS request\n alt Receiver acknowledges configured boundary\n Receiver-->>Export: Successful HTTP response\n Receiver->>SIEM: Parse, transform and index\n Operator->>SIEM: Search exact eventId\n SIEM-->>Operator: Searchable correlated copy\n else Receiver refuses or times out\n Receiver-->>Export: Error or timeout\n Export->>Export: Retry, then capture recoverable failure\n end\n~~~\n\nThere are three different facts to verify: **the source event exists**, **the\nreceiver acknowledged the request**, and **the transformed event is searchable\nin the intended index or table**. An HTTP 2xx response proves only the delivery\nboundary implemented by that receiver. It is not automatically proof that a\nparser, transformation, index or detection rule accepted the event.\n\n## Decide whether direct delivery is compatible\n\n| Receiver requirement | Recommended path | Why |\n| --- | --- | --- |\n| One HTTPS request containing one JSON object, with a static header or HMAC credential | Test direct delivery | This matches the current structured-JSON worker closely |\n| A provider-specific wrapper around the event | Use a narrow relay unless the exact endpoint accepts the native envelope | The relay owns the wrapper while preserving source identifiers |\n| Short-lived OAuth access tokens or managed identity | Use a provider-side relay | Token acquisition and refresh do not belong in a static credential field |\n| A JSON array or provider batch protocol | Use a relay that batches deliberately | Current delivery is one event per request; configured batch fields are reserved |\n| A syslog, agent, queue or private-network input | Use an adapter or relay inside that boundary | The application sends outbound HTTPS webhooks, not those transports |\n| CEF, LEEF or OCSF ingestion | Test actual emitted samples with the receiver | A format name does not prove field mapping, escaping, severity or class compatibility |\n\nPrefer the smallest component that makes the contracts compatible. A relay is\nnot a generic event platform: it should authenticate before parsing, preserve\nthe source event and correlation identifiers, perform one documented\ntransformation, expose bounded health signals and fail without silently\ndiscarding the event.\n\n## Choose the delivery contract\n\nThe following table is generated from the maintained SIEM configuration schema\nand resource specification. It distinguishes enforced values from reserved\nconfiguration so an accepted field is not mistaken for working delivery\nbehavior.\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#configurationMarkdown}}\n\n### Authentication values\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#authenticationValuesMarkdown}}\n\n### Wire-format values\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#formatValuesMarkdown}}\n\nChoose the simplest format the receiver can validate end to end:\n\n| Format | Use when | Verify before rollout |\n| --- | --- | --- |\n| Structured JSON | The receiver can preserve named fields and nested event data | Schema/field parsing, timestamps, identifiers and unknown-field handling |\n| CEF | The receiver has a tested CEF ingestion path | Header and extension parsing, escaping and the receiver's event classification |\n| LEEF | The receiver has a tested LEEF/QRadar path | Tab-delimited attributes, escaping and event mapping |\n| OCSF | The receiver consumes the emitted OCSF class documents | Class, activity, required fields and receiver validation for the actual event samples |\n\nDo not choose a format from its name alone. Preserve a receiver-tested sample\nfor each event family that matters to detection; syntactically accepted input\ncan still be mapped to the wrong fields or severity by the downstream product.\n\nAuthentication credentials are write-only secrets. A read returns a masked\nstored-credential marker, not the secret. Leaving that marker unchanged during\nan edit preserves the stored value; entering a new value replaces it. Never\ncopy the secret into a ticket or detection rule.\n\n## Configure filters from their exact values\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#filterValuesMarkdown}}\n\nThe optional \\`specificEventTypes\\` list is an **exact identifier allowlist**.\nIt is not a substring, prefix, regular expression or wildcard filter. Add an\nidentifier only after confirming that the corresponding event is emitted in the\napplication path you operate.\n\n## Configure delivery behavior\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#deliveryValuesMarkdown}}\n\nThe current worker posts **one event per HTTP request**. Do not configure a\nreceiver, load balancer or billing estimate on the assumption that \\`batchSize\\`\nor \\`batchWindowSeconds\\` reduces request volume. The\n\\`includeRawEventData\\` and \\`includeDeviceContext\\` flags are also reserved in\nthe current runtime: changing them does not remove those fields from the emitted\nenvelope. Treat data minimization at the receiver as necessary until those\nconfiguration controls are implemented end to end.\n\n## Filter for purpose and volume\n\nStart with the categories needed by the monitoring use case and a minimum\nseverity that preserves administrative and security-relevant activity. Add an\nevent-type allowlist only when the receiver intentionally needs that narrower\nset. An allowlist can silently exclude newly introduced event types, so record\nits owner and review it when the application's event catalogue changes.\n\nFilters govern future delivery copies; they do not delete the source audit\ntrail. A narrow SIEM feed is therefore not evidence that no other audit activity\nexists in the application.\n\n## Roll out deliberately\n\n1. Keep export disabled while the receiver, TLS and authentication are prepared.\n2. Start with structured JSON and a narrow event filter that includes one\n controlled administrative event.\n3. Enable export and perform the controlled action in the intended organization.\n4. Match the received event ID, timestamp, organization, outcome and correlation ID.\n5. Trigger a controlled event outside the filter and confirm it remains in the\n source trail but is not delivered to this receiver.\n6. Exercise an acknowledged receiver response and one safe temporary failure so\n ownership of retry/dead-letter recovery is known.\n7. Expand categories and lower the severity threshold only after the receiver\n handles expected volume and redaction.\n\nConfiguration is cached by the running application for up to five minutes.\nEnabling may therefore miss exports during that interval, and changing a\ndestination may continue sending to the former receiver until the cache expires.\nTreat a destination change as a security operation and verify the old receiver\nhas stopped receiving before closing the change.\n\nFor credential rotation or destination replacement, keep the change window and\nold/new receiver ownership explicit. Verify the current receiver accepts a new\ncontrolled event and the former receiver no longer receives selected traffic\nafter the cache window. Retain configuration approval, non-secret destination\nidentity, format/filter choices, test event and correlation IDs, delivery result\nand recovery owner—never the bearer token, API-key value or HMAC secret.\n\n## Format standards and receiver references\n\n- OpenText’s [Common Event Format implementation standard](https://www.microfocus.com/documentation/arcsight/arcsight-smartconnectors-24.4/cef-implementation-standard/)\n describes CEF header and extension construction. Validate the application’s\n actual event samples against the target connector rather than assuming every\n CEF consumer maps extensions identically.\n- IBM documents [LEEF event components](https://www.ibm.com/docs/en/qradar-on-cloud?topic=overview-leef-event-components)\n and [predefined LEEF attributes](https://www.ibm.com/docs/en/qradar-on-cloud?topic=overview-predefined-leef-event-attributes)\n for QRadar ingestion and field mapping.\n- The [OCSF schema browser](https://schema.ocsf.io) and\n [OCSF schema repository](https://github.com/ocsf/ocsf-schema) define the open\n event classes and attributes. Confirm the emitted class, activity and\n required fields for every selected event family.\n\nThese external standards describe receiver-side expectations. The generated\nconfiguration tables above remain the authority for values and behavior this\napplication actually supports.`,\n },\n {\n managedPath: 'security-and-audit/siem-splunk.md',\n unitRef: 'technical-documentation:unit/siem-splunk',\n sourceRefs: [\n 'saas-technical-doc:engine-content/siem-splunk',\n 'source:consumer-fact:organization-siem-export',\n ],\n markdown: `# Send audit events to Splunk\n\nSplunk HTTP Event Collector (HEC) accepts events over HTTPS with a token in the\n\\`Authorization\\` header. The application can supply that header, but its native\nstructured JSON body is a security-audit envelope—not Splunk’s HEC\n\\`{\"event\": ...}\\` wrapper. **Use a small controlled relay unless your chosen HEC\nendpoint and source type have been proven to accept and extract the exact body.**\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#markdown}}\n\n~~~mermaid\nflowchart LR\n audit[\"Organization audit event\"] --> exporter[\"Application SIEM export\"]\n exporter -->|\"JSON + authenticated HTTPS\"| relay[\"Owned HEC relay\"]\n relay -->|\"HEC event wrapper\"| hec[\"Splunk HEC\"]\n hec --> index[\"Dedicated index and source type\"]\n index --> search[\"Search by eventId and correlationId\"]\n~~~\n\n## Prepare Splunk\n\n1. Create a dedicated Splunk index or confirm the approved existing index.\n2. In Splunk Cloud or Splunk Enterprise, create an HEC token dedicated to this\n application organization and environment.\n3. Assign the token only to the intended index and choose a JSON-capable source\n type. Wait until token deployment is complete before testing.\n4. Record the HEC base URL, token owner, index, source type, rotation process and\n retention policy. Store the token only in approved secret stores.\n\nSplunk’s event endpoint expects a body shaped like:\n\n~~~json\n{\n \"time\": 1776631800,\n \"host\": \"application-production\",\n \"source\": \"application-security-audit\",\n \"sourcetype\": \"_json\",\n \"index\": \"security\",\n \"event\": {\n \"eventId\": \"7b45a61c-9bcc-4bf2-9a29-0f111bff6d07\",\n \"eventType\": \"user_login_failed\",\n \"organizationId\": \"org_example\",\n \"severity\": \"warning\"\n }\n}\n~~~\n\nThe relay owns this wrapper and any approved metadata; it must preserve the\napplication event object without renaming \\`eventId\\`, \\`correlationId\\`, actor,\norganization, timestamp, outcome or severity fields.\n\n### Choose the acknowledgement boundary\n\nA normal HEC success response confirms that HEC accepted the request. Splunk\nalso supports **indexer acknowledgement**, where a client submits a channel\nidentifier and later checks whether the event reached the indexing pipeline.\nIf the relay uses that mode, return success to the application only after the\nrelay’s documented durability boundary; do not hold the application request\nopen indefinitely while waiting for a search result.\n\nWhichever mode you choose, the operating proof is still an exact\n\\`eventId\\` search in the intended index. Record separately whether a failure\nhappened before HEC acceptance, while awaiting an indexer acknowledgement, or\nafter indexing during parsing and field extraction.\n\n## Configure the application-to-relay request\n\nRecommended application settings:\n\n| Setting | Value |\n| --- | --- |\n| Destination | Relay HTTPS URL dedicated to the organization/environment |\n| Authentication | \\`hmac_sha256\\` or a dedicated \\`api_key_header\\` |\n| Format | \\`json_structured\\` |\n| Delivery | One event per request; choose timeout/retry values below the relay’s bounded acknowledgement time |\n\nIf a controlled test proves direct HEC compatibility, configure:\n\n| Setting | Direct HEC value |\n| --- | --- |\n| \\`authMethod\\` | \\`api_key_header\\` |\n| \\`authHeaderName\\` | \\`Authorization\\` |\n| \\`authCredential\\` | The complete value \\`Splunk HEC_TOKEN\\`, including the \\`Splunk \\` prefix |\n| \\`webhookUrl\\` | The exact HEC event or raw endpoint validated by the Splunk owner |\n\nThe API-key-header mode sends the configured credential verbatim. Do not choose\n\\`bearer_token\\`: it would send \\`Authorization: Bearer ...\\`, which is not\nSplunk HEC token authentication.\n\n## Prove ingestion, not only HTTP acceptance\n\n1. Keep broad export disabled and select one controlled event type.\n2. Trigger the event and find the source audit row.\n3. Confirm relay/HEC HTTP acceptance without logging the token.\n4. Search the intended Splunk index for the exact \\`eventId\\`.\n5. Verify organization, timestamp, event type, severity, actor/outcome and\n correlation identifier.\n6. Trigger an event outside the filter and confirm it remains only in the source\n audit trail.\n7. Temporarily refuse one request, restore the receiver and prove dead-letter\n recovery without creating a duplicate indexed event.\n\n## Splunk documentation to keep with the runbook\n\n- Splunk’s [HTTP Event Collector examples](https://help.splunk.com/en/splunk-enterprise/get-data-in/collect-http-event-data/http-event-collector-examples)\n show the HEC authorization header, event wrapper and endpoint shapes used to\n validate the relay output.\n- Splunk’s [HEC indexer acknowledgement](https://help.splunk.com/en/splunk-enterprise/get-started/get-data-in/9.2/get-data-with-http-event-collector/about-http-event-collector-indexer-acknowledgment)\n documentation explains the optional channel and acknowledgement protocol.\n\nKeep the tested HEC endpoint, source type, acknowledgement mode and sample\nsearch beside these links. Provider documentation defines Splunk’s contract;\nthis guide defines the application envelope that must be conserved.`,\n },\n {\n managedPath: 'security-and-audit/siem-microsoft-sentinel.md',\n unitRef: 'technical-documentation:unit/siem-microsoft-sentinel',\n sourceRefs: [\n 'saas-technical-doc:engine-content/siem-microsoft-sentinel',\n 'source:consumer-fact:organization-siem-export',\n ],\n markdown: `# Send audit events to Microsoft Sentinel\n\nMicrosoft Sentinel commonly receives custom data through the Azure Monitor Logs\nIngestion API. That API requires a Data Collection Rule (DCR), a matching JSON\nschema and Microsoft Entra OAuth authorization. The application’s SIEM exporter\nuses a static outbound credential and posts one JSON object per event; it does\nnot acquire or refresh Azure OAuth tokens and does not wrap events as the JSON\narray expected by Logs Ingestion. **Use an Azure-hosted relay rather than pointing\nthe application directly at the Logs Ingestion API.**\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#markdown}}\n\n~~~mermaid\nflowchart LR\n app[\"Application SIEM export\"] -->|\"HMAC or API-key authenticated JSON\"| relay[\"Azure Function, Logic App or API Management relay\"]\n relay --> transform[\"Validate, transform and batch as an array\"]\n transform -->|\"Entra OAuth token\"| dcr[\"Azure Monitor DCR ingestion endpoint\"]\n dcr --> table[\"Log Analytics custom table\"]\n table --> sentinel[\"Microsoft Sentinel analytics\"]\n~~~\n\n## Prepare Azure Monitor and Sentinel\n\n1. Create a custom Log Analytics table whose columns preserve the application\n event identifiers, timestamp, organization, actor, outcome, severity and\n event-specific data needed by detections.\n2. Create a DCR with a direct Logs Ingestion endpoint (or a Data Collection\n Endpoint when private-link architecture requires it), the input stream and a\n transformation into the table.\n3. Create a relay identity and grant it only the DCR ingestion permission it\n needs. Keep Azure client credentials or managed identity inside Azure.\n4. Deploy an HTTPS relay that validates the application request **before**\n parsing, converts the event into the DCR input schema, sends a JSON array to\n Logs Ingestion and returns success only after the chosen delivery boundary.\n\n### Relay input contract\n\nUse \\`json_structured\\` so the relay receives the complete application envelope.\nFor HMAC authentication, validate:\n\n~~~text\nX-Signature-256: sha256=LOWERCASE_HEXADECIMAL_HMAC\n~~~\n\nCompute HMAC-SHA256 over the exact received bytes with the shared secret and use\na constant-time comparison. Do not parse and reserialize before verification.\nAlternatively, configure a dedicated API-key header accepted only by the relay.\n\nThe relay should emit a DCR record similar to:\n\n~~~json\n[\n {\n \"TimeGenerated\": \"2026-08-20T19:30:00.000Z\",\n \"EventId\": \"7b45a61c-9bcc-4bf2-9a29-0f111bff6d07\",\n \"CorrelationId\": \"req_01HXEXAMPLE\",\n \"OrganizationId\": \"org_example\",\n \"EventType\": \"user_login_failed\",\n \"Severity\": \"warning\",\n \"Outcome\": \"failure\"\n }\n]\n~~~\n\n## Configure and prove the path\n\n1. Configure the application destination as the relay URL, authentication as\n HMAC or API-key header, and format as structured JSON.\n2. Start with one exact event type and leave broad categories disabled.\n3. Trigger the controlled event and record its source \\`eventId\\`.\n4. Prove signature/API-key validation at the relay, DCR acceptance, arrival in\n the custom table and Sentinel queryability by the same \\`eventId\\`.\n5. Compare timestamp, organization, actor, outcome and severity with the source\n row; a transformed row must remain traceable.\n6. Refuse an invalid signature and malformed schema without forwarding either.\n7. Simulate an Azure ingestion failure, restore the path, re-enqueue one\n dead-letter row and verify the table contains one intended event.\n\nDo not store a short-lived Azure access token as the application’s static bearer\ncredential; token acquisition and renewal belong to the relay identity.\n\n## Microsoft documentation to keep with the runbook\n\n- The [Logs Ingestion API overview](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/logs-ingestion-api-overview)\n defines the endpoint, JSON-array and OAuth boundaries the relay must satisfy.\n- The [Data Collection Rule overview](https://learn.microsoft.com/en-us/azure/azure-monitor/data-collection/data-collection-rule-overview)\n explains the input stream, destination and transformation relationship.\n- [Data collection transformations](https://learn.microsoft.com/en-us/azure/azure-monitor/data-collection/data-collection-transformations)\n describes the KQL transformation applied before the target table.\n- Microsoft Sentinel’s [data connector reference](https://learn.microsoft.com/en-us/azure/sentinel/connect-data-sources)\n helps the security owner decide whether the resulting table should feed a\n custom connector, analytics rule or another supported ingestion route.\n\nPin the DCR immutable identifier, stream name, table, transformation revision\nand relay identity in the runbook. A portal display name alone is not enough to\nreconstruct or audit the delivery path.`,\n },\n {\n managedPath: 'security-and-audit/siem-elastic.md',\n unitRef: 'technical-documentation:unit/siem-elastic',\n sourceRefs: [\n 'saas-technical-doc:engine-content/siem-elastic',\n 'source:consumer-fact:organization-siem-export',\n ],\n markdown: `# Send audit events to Elastic\n\nElastic Filebeat’s \\`http_endpoint\\` input can receive an HTTPS POST containing a\nJSON object and can validate a fixed secret header or an HMAC signature. This is\na close match for the application’s one-event structured JSON delivery. Run the\nlistener behind a production TLS and network boundary; the example below is a\nstarting contract, not a complete Elastic deployment.\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#markdown}}\n\n## Configure the receiver\n\nThe following Filebeat shape places the application envelope at the document\nroot and validates a dedicated header:\n\n~~~yaml\nfilebeat.inputs:\n - type: http_endpoint\n enabled: true\n listen_address: 0.0.0.0\n listen_port: 8443\n url: /application-security-audit\n prefix: \".\"\n content_type: application/json\n secret.header: X-Application-SIEM-Token\n secret.value: \\${APPLICATION_SIEM_TOKEN}\n ssl.enabled: true\n ssl.certificate: /run/secrets/tls.crt\n ssl.key: /run/secrets/tls.key\n tags: [application-security-audit]\n~~~\n\nConfigure the application with:\n\n| Setting | Value |\n| --- | --- |\n| \\`webhookUrl\\` | Public/proxied HTTPS endpoint ending in \\`/application-security-audit\\` |\n| \\`authMethod\\` | \\`api_key_header\\` |\n| \\`authHeaderName\\` | \\`X-Application-SIEM-Token\\` |\n| \\`authCredential\\` | The same dedicated secret value, stored once |\n| \\`eventFormat\\` | \\`json_structured\\` |\n\nFor HMAC instead, configure the Elastic input’s HMAC header as\n\\`X-Signature-256\\`, type \\`sha256\\`, prefix \\`sha256=\\` and the same shared key;\nthen select \\`hmac_sha256\\` in the application. Keep either mechanism scoped to\none organization/environment.\n\n## Map and retain the event\n\nKeep the complete application envelope in a controlled namespace, then add\nElastic Common Schema (ECS) fields through an ingest pipeline. Do not destroy\nthe source value merely to make it resemble an ECS value.\n\n~~~mermaid\nflowchart LR\n accTitle: Preserve the source event while creating an Elastic search view\n accDescr: Filebeat receives the application JSON envelope. An ingest pipeline preserves it under an application audit namespace, copies only semantically compatible values into Elastic Common Schema fields, sends the document to a scoped data stream, and makes source and normalized identifiers available to searches and detections.\n receive[\"Filebeat HTTP endpoint\"] --> pipeline[\"Ingest pipeline\"]\n pipeline --> original[\"Preserved application.audit fields\"]\n pipeline --> ecs[\"Explicit ECS mappings\"]\n original --> stream[\"Scoped data stream\"]\n ecs --> stream\n stream --> search[\"Search, dashboards and detections\"]\n~~~\n\n| Application field | Safe Elastic treatment | Important condition |\n| --- | --- | --- |\n| \\`timestamp\\` | Copy to \\`@timestamp\\` | Parse as the source-event time; keep receiver ingestion time distinct |\n| \\`eventId\\` | Copy to \\`event.id\\` | Preserve as an exact keyword for correlation and deduplication |\n| \\`eventType\\` | Copy to \\`event.action\\` | Keep the original identifier unchanged |\n| \\`eventCategory\\` | Preserve under \\`application.audit.category\\` | Map to ECS \\`event.category\\` only when the value is translated to an allowed ECS category |\n| \\`severity\\` | Preserve the source label; optionally derive numeric \\`event.severity\\` | ECS severity is numeric, so a text value such as \\`warning\\` needs an explicit mapping |\n| \\`outcome\\` | Preserve the source value; copy to \\`event.outcome\\` only after validation | ECS restricts outcome values; do not copy an incompatible value blindly |\n| \\`correlationId\\` | Preserve under \\`application.audit.correlation_id\\` | Use \\`trace.id\\` only when the identifier truly represents the same distributed trace |\n| \\`organizationId\\` and \\`applicationId\\` | Preserve as exact scoped keywords | Use them in data-stream access controls and investigation filters |\n\nActor/user identifiers and authentication source remain important for\ninvestigation, but map them only after deciding whether each identifier denotes\nthe acting account, the affected account or another subject. A convenient\n\\`user.id\\` mapping that merges those roles makes investigations misleading.\n\nApply an ingest pipeline or index template deliberately. Do not let dynamic\nmapping turn identifiers into analyzed text or allow arbitrary event data to\ncause uncontrolled field growth.\n\n## Prove end-to-end behavior\n\n1. Run the receiver on a controlled endpoint and confirm TLS trust from the\n application runtime.\n2. Send one selected test event and find it in the source audit trail.\n3. Confirm the Elastic input acknowledges the request, then search by exact\n \\`eventId\\` in the target data stream/index.\n4. Compare organization, time, event type, severity, actor and outcome.\n5. Send a wrong header value or signature and confirm Elastic returns 401 and\n the document is absent.\n6. Return a temporary 503, restore the endpoint and prove dead-letter recovery\n without an unintended duplicate detection.\n7. Record receiver capacity for **one request per selected event**; application\n batching fields are currently reserved and do not reduce that rate.\n\n## Elastic documentation to keep with the runbook\n\n- The [Filebeat HTTP Endpoint input reference](https://www.elastic.co/docs/reference/beats/filebeat/filebeat-input-http_endpoint)\n defines JSON-object handling, secret headers, HMAC validation, response codes\n and acknowledgement options.\n- The [ECS event field reference](https://www.elastic.co/docs/reference/ecs/ecs-event)\n defines fields such as \\`event.id\\`, \\`event.action\\`, \\`event.category\\`,\n \\`event.outcome\\` and \\`event.severity\\`.\n- Elastic’s [custom fields guidance](https://www.elastic.co/docs/reference/ecs/ecs-custom-fields-in-ecs)\n and [ECS mapping guidelines](https://www.elastic.co/docs/reference/ecs/ecs-guidelines)\n explain how to preserve application-owned semantics without creating field\n conflicts.\n- The Elastic Security [SIEM field reference](https://www.elastic.co/docs/reference/security/fields-and-object-schemas/siem-field-reference)\n identifies fields used by detections and investigations; treat it as a\n consumer requirement, not permission to invent missing source meaning.\n\nVersion the index template and ingest pipeline with the runbook. Re-run the\ncontrolled-event proof after changing either one, because successful HTTP\ndelivery can coexist with a broken mapping or detection.`,\n },\n {\n managedPath: 'security-and-audit/operate-siem.md',\n unitRef: 'technical-documentation:unit/operate-and-troubleshoot-siem-delivery',\n sourceRefs: [\n 'saas-technical-doc:engine-content/operate-and-troubleshoot-siem-delivery',\n 'source:consumer-fact:organization-siem-export',\n ],\n 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.`,\n },\n {\n managedPath: 'security-and-audit/respond-to-leaked-credential.md',\n unitRef: 'technical-documentation:unit/respond-to-leaked-credential',\n sourceRefs: ['saas-technical-doc:engine-content/respond-to-leaked-credential'],\n markdown: `# Respond to a leaked credential\n\nA credential of this application has been exposed — an API key in a public repository, a token in a\nsupport ticket or a log, an OAuth client secret in a screenshot, or a person's password reused on a\nservice that was breached.\n\nEvery other page in this section explains ONE capability well. This one exists because an incident\nis not one capability: it is an ORDER. The costly mistakes here are not doing the wrong thing, they\nare doing the right things in the wrong sequence — investigating before containing, or revoking\nbefore you know what the credential reached.\n\n**Contain first. Assess second. Recover third.** Work down the page.\n\n## Before you start\n\nWrite down the exposure time you will use as the window's lower bound — when the credential first\nbecame readable by someone who should not have it, NOT when you found out. If you cannot establish\nit, use the credential's creation time. Every step below is bounded by that instant, and widening it\nlater means redoing the assessment.\n\n## 1 · Contain\n\nDo this before anything else, including before you finish reading the rest of this page. A credential\nyou are still investigating is a credential still being used.\n\n| What leaked | Do this |\n| --- | --- |\n| An API key | Revoke it — see [API key lifecycle](/access-and-identity/api-keys-lifecycle). Revocation takes effect for new requests; it does not retract a request already in flight |\n| An OAuth client secret, or a token issued to a client | [Operate and revoke delegated access](/access-and-identity/oauth-operate-and-revoke), and revoke the client's outstanding grants, not only the secret |\n| A person's password | Suspend the account — see [Suspend or remove a user](/user-administration/suspend-or-remove-user). Suspending ends their sessions; a password reset alone does not tell you whether someone else is already signed in |\n| A SCIM or directory token | Rotate at the identity provider, then in [SCIM configuration](/user-administration/scim-configure). Until both sides carry the new value, provisioning is stopped — that is the correct trade during containment |\n\n**Do not delete anything yet.** Deleting the API key, the client or the user removes rows the next\nstep reads. Revoke and suspend, which stop use while keeping the record.\n\nIf you do not yet know which credential leaked, suspend the narrowest thing that certainly covers it\nand widen only if the assessment says so. An over-broad containment is recoverable in minutes; a\nmissed one runs for as long as you are investigating.\n\n## 2 · Assess\n\nOnly now, and only inside the window you wrote down.\n\n1. **What did it reach?** [Investigate an audit event](/security-and-audit/investigate-event),\n filtered to the credential's own identifier rather than to a person — a leaked key acts under its\n own identity, and filtering by the human who created it will not show you its requests.\n2. **Did it change access?** [Review access and privileged changes](/security-and-audit/review-access-changes).\n This is the question that decides whether containment is finished: a credential that granted a\n role, added a member or registered a client has left something behind that revoking it does not\n remove.\n3. **Take the evidence out.** [Export a bounded audit window](/security-and-audit/export-audit-records)\n for the window, before retention or an investigation of your own moves it. Handle the export as\n the sensitive artefact it is — [Protect and retain audit evidence](/security-and-audit/protect-evidence).\n\nIf step 2 found a change, treat every artefact it created as also compromised and return to\n**Contain** for each one. That loop is the point of the ordering: a leaked key that minted a second\nkey is only half-contained when the first is revoked.\n\n## 3 · Recover\n\n- Issue the replacement credential and store it where the leaked one was not —\n [Create and store an API key](/access-and-identity/api-keys-create-and-store) states where a\n secret may and may not live.\n- Give the replacement the SMALLEST role that works. An incident is the cheapest moment to correct\n an over-broad credential, because whatever breaks is being watched.\n- Lift the containment you widened, narrowest first, confirming after each one.\n- If the account is a person's, require a second factor before returning it to service —\n [Multifactor enrollment and recovery](/access-and-identity/mfa-enrollment-and-recovery).\n\n## What this application cannot tell you\n\nThe audit trail records what reached THIS application. A credential leaked in one place is usually\nleaked for others: if the same secret, or a password reused from it, opens anything else you run,\nthis page's window is a lower bound on the incident, not its boundary.\n\nNor can the trail prove absence. A window with no suspicious request means nothing suspicious\n**reached this application** during it — not that the credential was unused, and not that your lower\nbound was early enough.`,\n },\n {\n managedPath: 'security-and-audit/protect-evidence.md',\n unitRef: 'technical-documentation:unit/protect-and-retain-audit-evidence',\n sourceRefs: ['saas-technical-doc:engine-content/protect-and-retain-audit-evidence'],\n markdown: `# Protect and retain audit evidence\n\nAudit evidence can contain identities, IP addresses, device context, role\nchanges and event-specific business identifiers. Its security value does not\nmake every copy safe or every reader appropriate.\n\n| Before you disclose or retain a copy | Successful result |\n| --- | --- |\n| Know the investigation purpose, evidence owner, authorized readers, retention rule and deletion date | The smallest useful evidence remains traceable and protected without creating an indefinite uncontrolled copy |\n\n~~~mermaid\nflowchart LR\n accTitle: Keep the authoritative audit trail separate from controlled copies\n accDescr: The application retains the immutable source audit row. An investigator may create a bounded JSON copy, SIEM delivery may create an operational monitoring copy, and archival may create a durable retention copy. Each downstream copy needs its own access, integrity, retention and deletion controls.\n source[\"Authoritative application audit row\"] --> review[\"In-product investigation\"]\n source --> bounded[\"Bounded JSON export\"]\n source --> siem[\"Organization SIEM copy\"]\n source --> archive[\"Durable archive copy\"]\n bounded --> controls[\"Named owner, access and deletion rule\"]\n siem --> controls\n archive --> controls\n~~~\n\nThe application audit row remains the source record. An exported file, SIEM\nevent or archive object is a separate copy with a separate custody lifecycle;\none copy's retention or deletion setting does not silently govern the others.\n\n## Know which copy you are handling\n\n| Evidence location | Primary purpose | Control to record |\n| --- | --- | --- |\n| Application audit trail | Authoritative investigation and access-review record | Who may search or export the organization scope |\n| Bounded JSON export | Small approved investigation or compliance review | Purpose, filters, recipient, protected location and deletion date |\n| SIEM destination | Continuous detection, correlation and operational response | Receiver access, delivery health, downstream retention and incident ownership |\n| Durable archive | Long-term governed retention | Retention basis, integrity checks, restoration procedure and legal-hold handling |\n\n## Preserve integrity and minimize disclosure\n\n- Keep event ID, timestamp, actor classification, organization, outcome and\n correlation fields unchanged.\n- Never add a credential or secret to event data, a support ticket or a SIEM rule.\n- Share the smallest time range and field set needed for the investigation.\n- Separate security evidence from operational logs and business history; each\n has a different purpose and access policy.\n- Record who exported or disclosed evidence and the approved reason.\n\nWhen a ticket or report needs only a few events, attach a redacted subset and\nretain a reference to the protected source copy. Do not edit the source evidence\nto make it easier to read. Explain redactions separately so another authorized\nreviewer can reproduce the selection.\n\n## Apply retention to every copy\n\nAudit rows are immutable: the resource exposes no update or delete operation.\nWhen archival is configured, records older than the archival horizon are copied\nto durable file storage; the primary audit rows are not deleted. When no\narchival horizon is configured, the primary store retains them indefinitely.\nProduction archival cannot be configured below one year.\n\nBefore retaining evidence, answer:\n\n1. Which policy, investigation, legal hold or regulatory purpose requires it?\n2. Which copy is authoritative for this use?\n3. Who owns access approval and periodic review?\n4. When may the copy be deleted, and who verifies deletion?\n5. How will an authorized reviewer verify that identifiers and timestamps were\n not changed?\n\n> **Archival is not deletion from the primary audit trail.** It creates another\n> durable copy after the configured horizon. Plan access, restoration and final\n> disposition for that copy explicitly.\n\n## Treat optional context carefully\n\nCorrelation ID connects events from one request to application logs and errors.\nClient-instance ID may connect activity across sessions only when the application\nhas explicitly enabled that context. Its absence is not a collection failure.\nFrontend service name may be absent for jobs, scheduled work and internal\noperations.\n\nApply the organization's retention, legal-hold, privacy and incident-response\npolicy to every exported or downstream copy. A SIEM retention rule does not\nchange the application's authoritative audit retention.\n\n## Before closing the evidence task\n\n- confirm the organization, environment, time range and event count;\n- preserve event and correlation identifiers unchanged;\n- record the evidence owner, approved recipients and purpose;\n- confirm the protected storage location and deletion or legal-hold rule;\n- remove temporary local copies and ticket attachments that are no longer\n required;\n- keep credentials and unrelated personal data out of the evidence package.`,\n },\n {\n managedPath: 'integrations.md',\n unitRef: 'technical-documentation:unit/integrations',\n sourceRefs: ['saas-technical-doc:engine-content/integrations'],\n markdown: `# Integrations\n\nAn integration connects this application to another system so that people do\nnot have to copy information or repeat the same action by hand. Start with the\noutcome you need, then choose the smallest contract that can deliver it safely.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Name one business outcome, the source of truth, the organization affected, the acting person or workload and who owns failures | The chosen connection proves one bounded allowed outcome, one expected refusal and a recovery path that does not expose credentials or repeat a business effect |\n\n## Which integration should you choose?\n\n| You need to… | Use | Why |\n| --- | --- | --- |\n| Read or change application data on demand | [REST API](/integrations/rest-api) | Your system sends a request and receives an immediate response |\n| Build a workflow in n8n, Zapier or Make | [Automation platforms](/integrations/automation-platforms) | The platform calls the REST API or receives a published event |\n| React when the application publishes an event | The Webhooks section, when available below | The application pushes a signed delivery to your receiver |\n| Connect Cursor, Codex or Claude Code | The AI coding tools section, when available below | The client discovers MCP tools available to its authenticated identity |\n| Give another AI client callable tools or exchange agent tasks | The Agent integrations section below | MCP covers tools; A2A covers messages and task lifecycles |\n\nDo not choose a protocol because its name is familiar. Choose it because its\ninteraction model matches the business outcome. A scheduled REST poll is not a\nreplacement for an event when timeliness matters; a webhook is not a command\nchannel; an MCP tool call is not an A2A conversation.\n\n~~~mermaid\nflowchart TD\n accTitle: Choose an integration contract from the intended outcome\n accDescr: Immediate request and response work uses REST. Event notification uses webhooks. Tool discovery and invocation uses MCP. Agent conversations and tasks use A2A.\n outcome[\"What must the other system accomplish?\"] --> immediate{\"Immediate request and response?\"}\n immediate -->|Yes| rest[\"REST API\"]\n immediate -->|No| event{\"React to an application event?\"}\n event -->|Yes| webhook[\"Webhook\"]\n event -->|No| agent{\"AI or agent interaction?\"}\n agent -->|Call advertised tools| mcp[\"MCP\"]\n agent -->|Exchange messages and tasks| a2a[\"A2A\"]\n~~~\n\nThe diagram is a starting point, not a permission decision. The identity used\nby the integration still needs access to the intended organization, resources\nand operations.\n\n## Keep the source of truth explicit\n\nDecide which system owns the final fact before writing synchronization logic.\nREST can retrieve or change current application state; a webhook announces that\nan event occurred; MCP invokes an advertised operation; A2A carries a message or\ntask. None of those contracts automatically makes the receiving copy\nauthoritative.\n\nAfter a timeout, duplicate or conflicting change, reconcile against the system\nthat owns the fact. If ownership is shared or unclear, define a human decision\npath rather than letting the last retry silently win.\n\n## Before you connect anything\n\n- Name the business outcome and the system that owns the authoritative state.\n- Use a separate identity and credential for each deployed workload.\n- Begin in a non-production organization with the least privilege required.\n- Decide how you will reconcile timeouts, duplicates and partially completed work.\n- Record correlation information without copying credentials or restricted data.\n\n## Prove the boundary before production\n\nStart with a harmless action whose correct result a person can recognize. Prove\nthe intended environment, identity, organization and response shape. Then prove\none expected refusal: another organization, an unavailable operation, an\ninvalid signature or insufficient authority must remain blocked.\n\nOnly after those checks should you add a mutation, automatic retry, schedule or\nproduction volume. For a state-changing path, deliberately simulate a lost\nresponse and show how authoritative state is read before another attempt.\n\nRetain the integration owner, deployed workload, non-secret credential\nidentifier, environment, organization, operation or event identity, outcome and\ncorrelation evidence. Define how the credential is rotated or revoked and who\nreceives an alert when the business result cannot be reconciled.\n\nIf you are building a new connection, begin with [Create your own integration](/integrations/create-your-own-integration). The API reference supplies exact paths and schemas after you have chosen the correct journey.`,\n },\n {\n managedPath: 'integrations/automation-platforms.md',\n unitRef: 'technical-documentation:unit/automation-platforms',\n sourceRefs: ['saas-technical-doc:engine-content/automation-platforms'],\n markdown: `# Automation platforms\n\nUse an automation platform when a business process must move information or\nstart work across systems without requiring a custom deployed service. This\nsection covers **n8n**, **Zapier** and **Make**. The application does not need a\nplatform-specific connector: each platform can call the published REST API,\nand it can receive application webhooks when a Webhooks section is available.\n\n## Start from the business event\n\nDescribe the automation in one sentence before opening the workflow editor:\n“When an approved record changes, create or update its counterpart in the\nreporting system.” That sentence identifies the trigger, the intended effect\nand the system that owns the final state.\n\n| The work starts when… | Begin with | Why |\n| --- | --- | --- |\n| A schedule, form or another system produces input | An authenticated REST request | The workflow controls when the application is read or changed |\n| This application publishes a relevant event | A webhook receiver | The workflow starts from the event instead of repeatedly polling |\n| A person presses a workflow button | A safe read, followed by an explicit write | The person can confirm scope before a change is made |\n\n~~~mermaid\nflowchart LR\n accTitle: Build an automation around one authoritative business outcome\n accDescr: A schedule, human action, or application event starts the workflow. The workflow validates the input, reads current application state, applies one intended effect, and records enough evidence to reconcile failures.\n trigger[\"Schedule, person or application event\"] --> validate[\"Validate input and organization\"]\n validate --> read[\"Read authoritative state\"]\n read --> decide{\"Change still required?\"}\n decide -->|No| finish[\"Record no change\"]\n decide -->|Yes| write[\"Apply one documented operation\"]\n write --> confirm[\"Confirm result and retain correlation\"]\n~~~\n\n## Choose your platform\n\n- [Connect n8n](/integrations/automation/n8n) when you want a visual workflow\n that can also be self-hosted and extended with technical nodes.\n- [Connect Zapier](/integrations/automation/zapier) when the business workflow\n already lives in Zaps and should use an API or webhook step.\n- [Connect Make](/integrations/automation/make) when you want to map a scenario\n visually and control HTTP request fields in a dedicated module.\n\n## Keep the first workflow deliberately small\n\nUse a dedicated credential for one environment and one workflow. Prove one\nread operation, then one write only if the business outcome requires it. Store\nthe credential in the platform's credential or connection store—not in a URL,\nordinary field, workflow name, execution note or shared screenshot.\n\nBefore enabling unattended runs, test invalid input, expired or revoked access,\ninsufficient permission, a timeout after a write and a duplicate trigger. The\nworkflow is production-ready only when an operator can determine whether the\nbusiness effect occurred without blindly repeating it.`,\n },\n {\n managedPath: 'integrations/automation/n8n.md',\n unitRef: 'technical-documentation:unit/connect-n8n',\n sourceRefs: [\n 'saas-technical-doc:engine-content/connect-n8n',\n 'source:companion-projection:application-connection',\n 'source:consumer-fact:access-api-keys',\n ],\n markdown: `# Connect n8n\n\nUse n8n when a visual workflow should read or change information in this\napplication. There is no application-specific n8n node to install: the workflow\nuses n8n's standard **HTTP Request** node and the REST API published in this\ndocumentation.\n\nThis guide first builds a manual, read-only workflow. By the end, one click in\nn8n will call one authenticated operation and show recognizable application\ndata in the node output. Only then will you connect a trigger or add a write.\n\n> **If the application should start the workflow when something happens,**\n> complete the read-only connection first, then follow **Start from an\n> application event** below. Do not poll repeatedly when a published webhook\n> already represents the event you need.\n\n## What do you need before starting?\n\nAsk the application administrator or integration owner for:\n\n- the server origin shown in this application's API reference;\n- one authenticated **GET** operation and its complete path;\n- the non-production organization and known data you may use for the test;\n- a dedicated API key with only the role accepted by that operation; and\n- an owner who can revoke the key if the workflow is abandoned or exposed.\n\nUse [Create and store an API key](/access-and-identity/api-keys-create-and-store)\nif the credential has not been prepared. Keep n8n and the application in the\nsame environment throughout the test.\n\n## Build the first read-only workflow\n\n### 1. Create an explicit test trigger\n\nCreate a new workflow and keep it inactive. Add a **Manual Trigger** so that the\napplication is contacted only when you choose **Execute workflow**. Name the\nworkflow after the business result and environment—for example, “Read approved\nrecords — test”—not after the credential.\n\n### 2. Add the application request\n\nAdd an **HTTP Request** node after the trigger, then complete these fields from\nthe same API-reference operation:\n\n| n8n field | Value to use | How to verify it |\n| --- | --- | --- |\n| **Method** | The operation's documented HTTP method, initially **GET** | It matches the operation heading in the API reference |\n| **URL** | \\`{{APPLICATION_CONNECTION_VALUE:baseUrl}}\\` followed by the operation's documented path | The origin appears once and the API path appears once |\n| **Authentication** | **Generic Credential Type**, then **Header Auth** | The key is stored as an n8n credential, not in the URL or workflow data |\n| **Send Headers** | Add **Accept** with value **application/json** | The request asks for the documented JSON response |\n| Query/path values | Only values required by the selected operation | Organization and resource identifiers are in the locations defined by the reference |\n\nWhen creating the **Header Auth** credential, use the maintained application\nheader contract below. Enter the header name and secret value in the credential\ndialog; do not construct them with an expression inside the node.\n\n~~~text\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#requestHeader}}\n~~~\n\nn8n's [HTTP Request node documentation](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.httprequest/)\nexplains the current node controls and generic credential options. If the\nlabels in your installed n8n version differ, use that documentation for the UI\nlocation while keeping the application request contract defined here.\n\n### 3. Execute and inspect the output\n\nSelect **Execute workflow**. The Manual Trigger and HTTP Request nodes should\ncomplete successfully, and the HTTP Request output panel should contain JSON\nmatching the response schema in the API reference.\n\nDo not treat a green node alone as proof. Confirm:\n\n- the output is from the intended application environment;\n- the data belongs to the intended organization;\n- the known record or collection result is present;\n- required fields have the types documented in the response schema; and\n- the API key is absent from the input, output and execution data panels.\n\n~~~mermaid\nsequenceDiagram\n accTitle: Build and prove the first n8n application workflow\n accDescr: An operator runs a manual trigger, n8n reads application data with a stored credential, the operator verifies the returned organization and schema, and only then replaces the trigger or adds a controlled business action.\n actor Operator\n participant n8n\n participant App as Application API\n Operator->>n8n: Execute inactive test workflow\n n8n->>App: Authenticated GET from HTTP Request node\n App-->>n8n: Documented JSON response\n n8n-->>Operator: Show node output\n Operator->>Operator: Verify environment, organization and known data\n Operator->>n8n: Add trigger or one controlled action\n~~~\n\nThe checkpoint in the diagram is the human verification after the first read.\nIt prevents an apparently successful workflow from being activated against the\nwrong organization or environment.\n\n## Prove the credential boundary\n\nCopy the HTTP Request node for this negative test. On the copy, temporarily set\nauthentication to **None** while leaving the URL and parameters unchanged. Run\nonly that node. The authenticated operation should return its documented\nauthentication refusal, normally **401**.\n\nDelete the unauthenticated copy after the test. If it returns the same protected\ndata as the authenticated node, stop: either the wrong operation was selected or\nthe access boundary needs investigation. Do not continue by adding a write.\n\n## Turn the read into a useful workflow\n\nConnect one decision or transformation step to the verified HTTP Request node.\nFor example, an **If** node can stop the workflow when the collection is empty,\nor a mapping step can select only the fields the next system is allowed to\nreceive.\n\nBefore adding a state-changing request, define all four items:\n\n1. the exact application state that should change;\n2. the condition that permits the change;\n3. the read operation that proves the final state; and\n4. what the workflow does when a write times out without a response.\n\nFor the first write, keep automatic retry disabled. Execute it once with known\ntest data, then read the target back. **A timeout is not proof that the write did\nnot happen**; use the read-back before deciding whether another request is\nneeded.\n\n## Start from an application event\n\nUse this path only when a Webhooks section is present in this documentation and\nthe application publishes the event you need.\n\n1. Add an n8n **Webhook** trigger and copy its **test URL**.\n2. Put n8n into test-listening mode.\n3. Configure a non-production application webhook endpoint for that URL.\n4. Send one controlled event and inspect the received request before mapping\n any fields.\n5. Verify the application's signature and deduplicate the delivery before a\n downstream action.\n6. Publish the n8n workflow, copy its **production URL**, and update the\n application endpoint. The temporary test URL is not the production address.\n\nFollow [Verify a webhook delivery](/integrations/webhooks/verify-delivery) for\nthe application trust boundary. n8n's\n[Webhook workflow guide](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.webhook/workflow-development/)\nexplains its test and production URL lifecycle.\n\n## When the workflow does not work\n\n| What you see in n8n | Most likely boundary | What to check next |\n| --- | --- | --- |\n| Connection or TLS error | Server/network | Confirm the API-reference server origin is reachable from the n8n host |\n| **401** response | Credential transport or lifecycle | Confirm Header Auth is selected and the stored key is active; never expose the value while checking |\n| **403** response | Role, organization or operation authority | Compare the key's approved role with the operation requirement |\n| **404** response | Identifier, organization scope or visibility | Confirm the target exists in the application and the path values came from the same environment |\n| Green node, wrong records | Scope or mapping | Stop the workflow and correct organization, filters or response mapping before adding downstream nodes |\n| Timeout after a write | Ambiguous business result | Read the application state; do not repeatedly execute the write node |\n| Webhook works only in test mode | URL lifecycle | Publish the workflow and configure the production URL |\n\nUse [Troubleshoot an API request](/integrations/rest/troubleshoot) when the\nHTTP response needs deeper diagnosis.\n\n## Before activating the workflow\n\n- Replace the Manual Trigger only after the read and negative test pass.\n- Keep the application key in n8n's credential store and restrict who can edit\n or use that credential.\n- Pin the server, organization and workflow purpose; do not make them silently\n depend on whichever item ran previously.\n- Validate required fields before a write and reject unexpected values.\n- Define failed-execution alerts, an accountable operator and a revocation\n procedure.\n- Test a revoked key, insufficient permission, invalid input and an unavailable\n dependency.\n- Retain non-secret operation, status, time and correlation evidence so an\n operator can reconcile the business result.`,\n },\n {\n managedPath: 'integrations/automation/zapier.md',\n unitRef: 'technical-documentation:unit/connect-zapier',\n sourceRefs: [\n 'saas-technical-doc:engine-content/connect-zapier',\n 'source:companion-projection:application-connection',\n 'source:consumer-fact:access-api-keys',\n ],\n markdown: `# Connect Zapier\n\nUse Zapier when an existing Zap should read or change information in this\napplication. There is no application-specific Zapier connector to install. For\nan authenticated request, use **API by Zapier** so the API key lives in an app\nconnection instead of a visible Zap step.\n\nThis guide first creates one read-only action in an inactive Zap. You will test\nit with a known record, prove the authentication boundary, and only then connect\nthe action to a real trigger or add a write.\n\n> **Choose the other direction when the application starts the work.** If a\n> published application event should start the Zap, follow **Receive an\n> application event** below after the API connection proof.\n\n## Prepare one safe test\n\nBefore opening the Zap editor, collect:\n\n- the server origin and one authenticated **GET** operation from this\n application's API reference;\n- the non-production organization and one known record or collection result;\n- a dedicated API key with only the role accepted by that operation; and\n- an accountable owner for the Zap and credential.\n\nZapier's [current API-request comparison](https://help.zapier.com/hc/en-us/articles/44391646192397-Ways-to-make-API-requests-in-Zapier)\nexplains why **API by Zapier** is the appropriate choice for APIs that use an API\nkey: the credential is stored in an app connection. **Webhooks by Zapier** keeps\ncredentials in step fields and is not the preferred authenticated-request path.\n\n## Build the first read-only action\n\n### 1. Keep the Zap inactive\n\nCreate a Zap with the business outcome and environment in its name. Use a\ntrigger that can provide one controlled test item, but do not publish or turn on\nthe Zap yet.\n\n### 2. Add API by Zapier\n\nAdd **API by Zapier** as the action app and choose **API Request**. Create a new\napp connection for this application and environment. Configure the API key as a\nstatic header using the maintained application contract:\n\n~~~text\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#requestHeader}}\n~~~\n\nThe connection should own the secret. Do not copy the key into the request URL,\nZap name, mapped test data, notes or an ordinary step field.\n\n### 3. Enter the request from the API reference\n\nComplete the API Request action from one operation in the current reference:\n\n| Zapier field | Value to use | Verification |\n| --- | --- | --- |\n| Method | The documented method, initially **GET** | It matches the operation heading |\n| URL | \\`{{APPLICATION_CONNECTION_VALUE:baseUrl}}\\` plus the operation's documented path | Origin and API prefix each appear once |\n| Headers | **Accept: application/json** plus connection-managed authentication | No API key is visible in the Zap step |\n| Parameters | Only required query/path values | Organization and record values are in the documented locations |\n| Body | Empty for the selected read unless the operation explicitly documents one | No response field was copied back as an invented request field |\n\n### 4. Test and inspect the action\n\nRun **Test step**. A useful connection proof has all of these results:\n\n- Zapier reports the operation's documented success status;\n- the output JSON matches the response schema;\n- the known record or collection result belongs to the intended organization;\n- the application key does not appear in the action input or output; and\n- later Zap steps can select the stable application identifier they need.\n\nDo not use a human-readable label as the reconciliation key when the response\nprovides a stable identifier.\n\n## Prove the request is protected\n\nAdd a temporary **Webhooks by Zapier — GET** action with the same read URL and\nparameters but **no authentication**. Test only that action. The protected\noperation should return its documented authentication refusal, normally\n**401**. Delete the temporary action after the proof.\n\nIf the unauthenticated action returns the protected data, stop. Confirm that you\nselected the intended authenticated operation before adding a write or enabling\nthe Zap.\n\n## Add one controlled business action\n\nPlace a **Filter** or equivalent decision step before any state-changing\nrequest. The filter should reject missing identifiers, the wrong organization\nand any business condition that does not justify the change.\n\nFor the first write:\n\n1. copy the exact method, schema and operation path from the API reference;\n2. test with one recognizable non-production record;\n3. keep automatic repetition disabled;\n4. read the record back from the application; and\n5. retain the returned application identifier for reconciliation.\n\n**A Zapier timeout is not proof that the application made no change.** Read the\nauthoritative record before replaying the action or the complete Zap.\n\n## Receive an application event\n\nUse this path only when a Webhooks section is published here and the application\npublishes the event you need.\n\n1. Add **Webhooks by Zapier — Catch Raw Hook** when the trigger must preserve\n the request needed for signature verification; otherwise use **Catch Hook**.\n2. Copy the unique hook URL and treat it as sensitive connection information.\n3. Configure one non-production application webhook endpoint for that URL.\n4. Send one controlled event and inspect the sample before mapping fields.\n5. Verify the application signature and deduplicate the delivery before any\n business effect.\n\nThe [official Catch Hook guide](https://help.zapier.com/hc/en-us/articles/8496288690317-Trigger-Zap-workflows-from-webhooks)\nexplains the trigger URL and sample lifecycle. If the selected Zapier trigger\ncannot preserve the raw signed request required by this application's\nverification contract, receive and verify the event in a controlled service,\nthen forward only the trusted fields the Zap needs.\n\n~~~mermaid\nflowchart TD\n accTitle: Choose a safe Zapier connection\n accDescr: A Zap either calls the application through a stored API connection or receives a verified application event. Both paths validate scope and input before mapping data into downstream actions.\n need{\"What starts the Zap?\"}\n need -->|Zap schedule or another app| request[\"Stored API connection\"]\n request --> api[\"Documented REST operation\"]\n need -->|Application event| hook[\"Catch Hook or verified receiver\"]\n hook --> verify[\"Verify and deduplicate event\"]\n api --> map[\"Validate and map result\"]\n verify --> map\n map --> downstream[\"One intended downstream effect\"]\n~~~\n\n## When a test or run fails\n\n| What Zapier shows | Check first | Safe next action |\n| --- | --- | --- |\n| Connection failure | Server origin, network and TLS | Repair reachability before changing the app connection |\n| **401** | API by Zapier connection and key lifecycle | Reconnect the correct active key without revealing it in the step |\n| **403** | Required role, organization and operation authority | Request only the approved missing authority; do not switch to an administrator credential |\n| **404** | Operation path, record identifier and organization visibility | Confirm the record in the application and the selected environment |\n| Test succeeds, later mapping is empty | Response schema and selected output path | Compare the test output with the current operation response before remapping |\n| Zap reports success, record is missing | Each step's input/output and authoritative application state | Locate the first divergent step; do not replay the entire Zap blindly |\n| Duplicate business effect | Trigger/delivery identity and reconciliation key | Stop the Zap and add deduplication before another event is accepted |\n\n## Before turning the Zap on\n\n- Pin the connection to one application environment and organization.\n- Confirm who can use the app connection and who owns revocation.\n- Test invalid input, a revoked key, insufficient permission and an unavailable\n dependency.\n- Define how a timeout after a write is reconciled before Zapier retries.\n- Prevent two trigger items or webhook deliveries from producing two business\n effects.\n- Send failure alerts with operation, time, status and correlation evidence—but\n no credential or unrestricted sensitive payload.`,\n },\n {\n managedPath: 'integrations/automation/make.md',\n unitRef: 'technical-documentation:unit/connect-make',\n sourceRefs: [\n 'saas-technical-doc:engine-content/connect-make',\n 'source:companion-projection:application-connection',\n 'source:consumer-fact:access-api-keys',\n ],\n markdown: `# Connect Make\n\nUse Make when a visual scenario should read or change information in this\napplication. There is no application-specific Make app to install. The scenario\nuses **HTTP — Make a request** with a credential stored in a Make keychain.\n\nThis guide builds one read-only module in an inactive scenario, verifies its\noutput and access boundary, and only then adds a schedule, downstream module or\napplication webhook.\n\n## Prepare the connection proof\n\nCollect these values before opening the Scenario Builder:\n\n- the server origin and one authenticated **GET** operation from this\n application's API reference;\n- the intended non-production organization;\n- one record or collection result you can recognize;\n- a dedicated API key with only the role accepted by the operation; and\n- the person who owns the scenario and can revoke its credential.\n\n## Build the first read-only scenario\n\n### 1. Add the HTTP module\n\nCreate a scenario, keep scheduling **off**, and add **HTTP — Make a request**.\nName the scenario after its business result and environment rather than after\nthe credential.\n\n### 2. Store the credential\n\nIn the module's **Credentials** field, choose API-key authentication and create\na dedicated keychain. Put the complete application key in the key field, choose\nheader placement, and use **Authorization** as the parameter name. The resulting\nrequest must contain:\n\n~~~text\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#requestHeader}}\n~~~\n\nUse the dedicated credential field. Do not duplicate the key in ordinary\nheaders, query parameters, the scenario name, notes or mapped bundles.\n\n### 3. Configure the documented request\n\nComplete the remaining module fields from the same API-reference operation:\n\n| Make field | Value to use | Verification |\n| --- | --- | --- |\n| URL | \\`{{APPLICATION_CONNECTION_VALUE:baseUrl}}\\` plus the operation's documented path | The scheme, origin and API prefix each appear once |\n| Method | The documented method, initially **GET** | It matches the operation heading |\n| Headers | Add **Accept: application/json** | Authentication remains in **Credentials**, not duplicated here |\n| Query parameters | Only parameters accepted by the operation | Organization and record values are in documented locations |\n| Body content type | No body for the selected read unless documented | For later writes, choose the exact documented content type |\n| Parse response | **Yes** | Returned fields become available for mapping after a successful run |\n\nMake's [current HTTP app documentation](https://apps.make.com/http) defines the\nmodule fields, credential types, response parsing and pagination controls. Do\nnot select a pagination mode until the application's exact collection operation\ndocuments the matching contract.\n\n### 4. Run once and inspect the bundle\n\nSelect **Run once** and execute the module. A successful connection proof means:\n\n- the module returns the operation's documented success status;\n- the parsed output matches the documented response shape;\n- the known record or collection belongs to the intended organization;\n- the API key is absent from the module input/output bundles; and\n- the stable application identifier is available for later modules.\n\nDo not add mappings while the result belongs to the wrong environment or\norganization, even when the module is green.\n\n## Prove the authentication boundary\n\nClone the HTTP module for a temporary negative test. Remove **Credentials** from\nthe copy without adding an Authorization header, then run only that module. The\nprotected operation should return the documented authentication refusal,\nnormally **401**. Delete the unauthenticated copy after the test.\n\nIf it returns the protected data, stop and verify that the selected operation\nactually requires authentication before continuing.\n\n## Add one controlled change\n\nBefore adding a state-changing HTTP module, define the exact condition that\npermits it and add a Make filter that rejects missing identifiers, the wrong\norganization and incomplete source data.\n\nRun the first write once with a recognizable non-production record. Then read\nthe target back from the application. **A connection loss or timeout does not\nprove that the write failed**; reconcile current state before allowing Make to\nrepeat the module.\n\n## Receive an application event\n\nUse this path only when a Webhooks section is present here and the application\npublishes the event you need.\n\n1. Add **Webhooks — Custom webhook**, select **Add**, give the webhook a name,\n and copy the generated URL.\n2. In **Advanced settings**, enable **Get request headers** and **JSON\n pass-through** when required by the application's raw-body verification\n contract.\n3. Select **Run once** so Make listens for a controlled sample.\n4. Configure one non-production application webhook endpoint and send one known\n event.\n5. Verify the application signature and deduplicate the delivery before a\n downstream business action.\n\nMake's [current Webhooks documentation](https://apps.make.com/gateway) explains\nthe unique URL, **Run once**, data structures, request headers and JSON\npass-through controls. A generated Make data structure is an editing aid, not a\ntrust decision. If the module cannot preserve the exact signed request required\nby this application's verification contract, receive and verify it in a\ncontrolled service first, then forward only trusted fields to Make.\n\n~~~mermaid\nsequenceDiagram\n accTitle: Move a Make scenario from a controlled test to operation\n accDescr: The operator stores an API key in a Make keychain, proves one application read, optionally captures one verified webhook sample, maps only required values, then schedules or activates the scenario with failure handling.\n participant Operator\n participant Make\n participant App as Application\n Operator->>Make: Create API-key keychain\n Make->>App: Safe documented read\n App-->>Make: Parsed JSON response\n App->>Make: Optional controlled webhook event\n Operator->>Make: Validate mapping and error route\n Operator->>Make: Activate scenario\n~~~\n\n## When the scenario does not work\n\n| What Make shows | Check first | Safe next action |\n| --- | --- | --- |\n| Connection or TLS error | Server origin and reachability from Make | Repair the connection before changing the keychain |\n| **400** | Required values and mapped request body | Compare each submitted field with the current operation schema |\n| **401** | Keychain selection and key lifecycle | Attach the correct active keychain without exposing its value in headers |\n| **403** | Required role, organization and operation authority | Request only the approved missing authority; do not switch to an administrator key |\n| **404** | Operation path, identifier and organization visibility | Confirm the target and environment in the application |\n| Parsed field disappears | Raw response and current response schema | Correct the mapping after establishing whether the contract or selected path changed |\n| Timeout after a write | Authoritative application state | Read the target before repeating the module |\n| Webhook bundle lacks signed material | Request-header and JSON pass-through settings | Stop downstream actions until the verification boundary can be preserved |\n\n## Before scheduling or activating\n\n- Pin the scenario, keychain and webhook to one environment and organization.\n- Keep one credential per workload so it can be rotated or deactivated alone.\n- Add an error route that distinguishes invalid input, access refusal,\n throttling and unavailable dependencies.\n- Test a revoked key, insufficient permission, malformed input and a timeout\n after a controlled write.\n- Deduplicate triggers before producing a downstream business effect.\n- Retain application identifiers, status, time and correlation evidence—not\n credentials or unrestricted request/response bodies.`,\n },\n {\n managedPath: 'integrations/ai-coding-tools.md',\n unitRef: 'technical-documentation:unit/ai-coding-tools',\n sourceRefs: [\n 'saas-technical-doc:engine-content/ai-coding-tools',\n 'source:companion-projection:application-connection',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/ai-tools/cursor.md',\n unitRef: 'technical-documentation:unit/connect-cursor',\n sourceRefs: [\n 'saas-technical-doc:engine-content/connect-cursor',\n 'source:companion-projection:application-connection',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/ai-tools/codex.md',\n unitRef: 'technical-documentation:unit/connect-codex',\n sourceRefs: [\n 'saas-technical-doc:engine-content/connect-codex',\n 'source:companion-projection:application-connection',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/ai-tools/claude-code.md',\n unitRef: 'technical-documentation:unit/connect-claude-code',\n sourceRefs: [\n 'saas-technical-doc:engine-content/connect-claude-code',\n 'source:companion-projection:application-connection',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/agents.md',\n unitRef: 'technical-documentation:unit/agent-interoperability',\n sourceRefs: ['saas-technical-doc:engine-content/agent-interoperability'],\n markdown: `# Agent integrations\n\nUse an agent integration when software should choose or coordinate work through\nan AI-facing contract rather than through a fixed REST workflow. The application\ncan expose two different models:\n\n- **Model Context Protocol (MCP)** lets an AI client discover and call\n authorized application operations as tools.\n- **Agent-to-Agent (A2A)** lets a remote agent exchange messages and manage work\n that may continue as a task.\n\nThey use the application's identity and access boundaries, but they do not have\nthe same purpose, state or recovery model.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Name the business outcome, the person or workload authorizing it, the organization in scope, the maximum acceptable autonomy and the authoritative source used after uncertainty | The client uses the protocol that matches the work, sees only its authorized catalogue or agent, proves one harmless interaction and cannot repeat a state-changing effect merely because a response was lost |\n\n## Choose the interaction model\n\n| Question | MCP | A2A |\n| --- | --- | --- |\n| What does the client discover? | A caller-specific tool catalogue | An agent card describing the agent and its skills |\n| What is the primary interaction? | One tool invocation with structured arguments | A message that may produce a response or an asynchronous task |\n| What must be correlated? | Tool call, identity and application operation | Conversation context, task, agent instance and identity |\n| Where should you start? | The MCP connection guide, when this application publishes MCP tools | The A2A connection guide, when this application publishes A2A skills |\n\nChoose MCP when the desired work can be expressed as a known application\noperation with structured arguments and an immediate result. Choose A2A when\nthe caller needs a conversation, an agent-selected skill or a task identity that\ncan be read, streamed or cancelled later. Do not use A2A merely to wrap a fixed\nAPI call, and do not use MCP when the real operating requirement is a\nlong-running conversational task.\n\n~~~mermaid\nflowchart TD\n accTitle: Choose and constrain an application agent integration\n accDescr: An integration owner starts from the business outcome, chooses structured tool invocation or conversational task work, establishes the intended identity and organization, proves a harmless interaction, then adds bounded autonomy with authoritative reconciliation.\n outcome[\"Name one business outcome\"] --> mode{\"Known operation with immediate result?\"}\n mode -->|Yes| mcp[\"Use MCP tool discovery and invocation\"]\n mode -->|No, conversation or task| a2a[\"Use A2A message and task lifecycle\"]\n mcp --> identity[\"Bind one identity, audience and organization\"]\n a2a --> identity\n identity --> proof[\"Prove one harmless allowed action and one refusal\"]\n proof --> impact{\"State-changing or high impact?\"}\n impact -->|No| operate[\"Operate with bounded rate and evidence\"]\n impact -->|Yes| approval[\"Require approval and reconciliation rule\"]\n approval --> operate\n~~~\n\nIn both cases, a valid credential does not grant universal access. The active\norganization, roles, resource visibility, operation policy and any approval\nrequirement still apply.\n\nThe connection guides available below are generated from this application's\nown executable configuration. If one protocol is not configured, its guide is\nomitted instead of presenting a connection path that cannot work.\n\n## Choose the acting identity\n\nDecide whether the agent acts as a dedicated machine workload or on behalf of a\nperson. A machine identity is appropriate for scheduled or service-owned work;\na delegated identity is appropriate when a person knowingly authorizes the\nclient. Do not let a developer's administrator session become the production\ncredential for an unattended agent.\n\nKeep four values aligned throughout the connection:\n\n1. the application environment and server address;\n2. the selected MCP server or A2A agent instance, when a named instance is used;\n3. the credential audience and acting identity;\n4. the active organization and roles required for the intended work.\n\nA catalogue or agent card is discovery evidence, not an access grant. The\nspecific tool call, message or task operation still applies authorization and\nscope checks.\n\n## Set a safe autonomy boundary\n\nBegin with read-only work in one non-production organization. Add mutations\nonly after you have tested refusal, validation failure, timeout and an ambiguous\noutcome. Before repeating a state-changing action, read the authoritative state\nand determine whether the first attempt already applied.\n\nDefine the boundary explicitly:\n\n- which tools or agent skills may be used;\n- which organizations and resource types are in scope;\n- whether a person must approve a state-changing or high-impact step;\n- the maximum call or turn rate and spending/budget posture;\n- what result requires an authoritative read before another attempt;\n- who can disable the credential or client during an incident.\n\nTest at least one allowed read, one unavailable tool or skill, one insufficient-\nauthority refusal and one malformed input. For a mutation, test a lost or\nambiguous response in a safe scope and demonstrate reconciliation before\nallowing automatic repetition.\n\n## Separate model output from application truth\n\nTool results, agent messages and artifacts are inputs to the client. Validate\ntheir structured shape and treat any embedded instructions or links as\nuntrusted content. A model's statement that a change succeeded is not proof;\nread the authoritative application record and preserve the application-side\ncorrelation or audit evidence.\n\nKeep bearer and refresh credentials out of prompts, conversation transcripts,\ntool arguments and browser-accessible storage. Agent logs are useful diagnostic\nevidence, but they do not replace the application's authoritative audit trail.\n\n## Choose the next guide\n\n- **Connect an MCP client** — published in this section when the application\n exposes an MCP tool surface — for caller-specific tool discovery and\n structured application operations.\n- **Connect an A2A agent** — published in this section when the application\n exposes an A2A agent surface — for conversations and task lifecycle\n management.\n- [Create your own integration](/integrations/create-your-own-integration) when\n a deterministic REST or webhook workflow may be a better fit.`,\n },\n {\n managedPath: 'integrations/create-your-own-integration.md',\n unitRef: 'technical-documentation:unit/first-request',\n sourceRefs: [\n 'saas-technical-doc:engine-content/first-request',\n 'source:companion-projection:application-connection',\n 'source:consumer-fact:access-api-keys',\n ],\n 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\nThe origin below is this application's own, so the only thing left to supply is\nthe operation path from the API reference and your key. The authorization line\nis the application's maintained API-key transport contract.\n\n~~~bash\ncurl --fail-with-body \\\n --url \"{{APPLICATION_CONNECTION_VALUE:baseUrl}}<documented-operation-path>\" \\\n {{CONSUMER_FACT:source:consumer-fact:access-api-keys#curlRequestHeader}} \\\n --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.`,\n },\n {\n managedPath: 'integrations/rest-api.md',\n unitRef: 'technical-documentation:unit/common-rest-api',\n sourceRefs: [\n 'saas-technical-doc:engine-content/common-rest-api',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/rest/conventions.md',\n unitRef: 'technical-documentation:unit/rest-api-conventions',\n sourceRefs: [\n 'saas-technical-doc:engine-content/rest-api-conventions',\n 'source:companion-projection:application-connection',\n 'source:consumer-fact:access-api-keys',\n 'source:consumer-fact:rest-conventions',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/rest/send-request.md',\n unitRef: 'technical-documentation:unit/send-api-request',\n sourceRefs: [\n 'saas-technical-doc:engine-content/send-api-request',\n 'source:companion-projection:application-connection',\n 'source:consumer-fact:access-api-keys',\n ],\n 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=\"{{APPLICATION_CONNECTION_VALUE:baseUrl}}\" # this application's own origin\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 organization id and the key with yours; the base URL above is already this application's. 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).`,\n },\n {\n managedPath: 'integrations/rest/read-collections.md',\n unitRef: 'technical-documentation:unit/work-with-api-collections',\n sourceRefs: [\n 'saas-technical-doc:engine-content/work-with-api-collections',\n 'source:consumer-fact:rest-conventions',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/rest/write-and-reconcile.md',\n unitRef: 'technical-documentation:unit/write-and-reconcile-api-changes',\n sourceRefs: [\n 'saas-technical-doc:engine-content/write-and-reconcile-api-changes',\n 'source:consumer-fact:rest-conventions',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/rest/troubleshoot.md',\n unitRef: 'technical-documentation:unit/troubleshoot-api-request',\n sourceRefs: [\n 'saas-technical-doc:engine-content/troubleshoot-api-request',\n 'source:consumer-fact:access-api-keys',\n 'source:consumer-fact:rest-conventions',\n ],\n 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: the organization's subscription does not include the capability, or has reached its limit for it. Changing a role will not clear either one.\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.`,\n },\n {\n managedPath: 'integrations/webhooks.md',\n unitRef: 'technical-documentation:unit/webhooks',\n sourceRefs: [\n 'saas-technical-doc:engine-content/webhooks',\n 'source:companion-projection:application-integration',\n 'source:consumer-fact:outbound-webhooks',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/webhooks/configure-and-test.md',\n unitRef: 'technical-documentation:unit/configure-and-test-webhook-endpoint',\n sourceRefs: [\n 'saas-technical-doc:engine-content/configure-and-test-webhook-endpoint',\n 'source:consumer-fact:outbound-webhooks',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/webhooks/verify-delivery.md',\n unitRef: 'technical-documentation:unit/verify-webhook-delivery',\n sourceRefs: [\n 'saas-technical-doc:engine-content/verify-webhook-delivery',\n 'source:consumer-fact:outbound-webhooks',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/webhooks/operate-deliveries.md',\n unitRef: 'technical-documentation:unit/operate-webhook-deliveries',\n sourceRefs: [\n 'saas-technical-doc:engine-content/operate-webhook-deliveries',\n 'source:consumer-fact:outbound-webhooks',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/webhooks/troubleshoot.md',\n unitRef: 'technical-documentation:unit/troubleshoot-webhook-deliveries',\n sourceRefs: [\n 'saas-technical-doc:engine-content/troubleshoot-webhook-deliveries',\n 'source:consumer-fact:outbound-webhooks',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/mcp.md',\n unitRef: 'technical-documentation:unit/mcp-integrations',\n sourceRefs: [\n 'saas-technical-doc:engine-content/mcp-integrations',\n 'source:companion-projection:application-connection',\n 'source:companion-projection:application-integration',\n ],\n 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.`,\n },\n {\n managedPath: 'integrations/a2a.md',\n unitRef: 'technical-documentation:unit/a2a-integrations',\n sourceRefs: [\n 'saas-technical-doc:engine-content/a2a-integrations',\n 'source:companion-projection:application-connection',\n ],\n 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.`,\n },\n] as const;\n"]}