@picked/client 0.0.1-dev.1785305085063 → 0.0.1-dev.1785908062293

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 (291) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/api-03c5jvVk.js +38 -0
  3. package/dist/api-CQxCVIrm.cjs +1 -0
  4. package/dist/cjs/form/index.js +1 -1
  5. package/dist/cjs/index.js +2 -2
  6. package/dist/cjs/plugins/dom-observer/index.js +1 -1
  7. package/dist/cjs/plugins/dynamic-experiences/index.js +1 -1
  8. package/dist/cjs/server/index.js +1 -1
  9. package/dist/docs/explanation/conditions-and-the-logic-engine.md +94 -0
  10. package/dist/docs/explanation/feature-flag-allocation.md +176 -0
  11. package/dist/docs/explanation/how-picked-works.md +124 -0
  12. package/dist/docs/explanation/how-pickedql-works.md +76 -0
  13. package/dist/docs/explanation/pages-and-flows.md +64 -0
  14. package/dist/docs/explanation/the-content-model.md +77 -0
  15. package/dist/docs/explanation/the-two-apis.md +68 -0
  16. package/dist/docs/explanation/why-server-side-rendering.md +76 -0
  17. package/dist/docs/explanation/workspaces-and-versions.md +71 -0
  18. package/dist/docs/how-to/add-a-step-field-or-action.md +43 -0
  19. package/dist/docs/{pickedql/examples.md → how-to/analytics/index.md} +53 -28
  20. package/dist/docs/how-to/archive-or-delete-a-workspace.md +46 -0
  21. package/dist/docs/how-to/authenticate-with-a-magic-link.md +40 -0
  22. package/dist/docs/how-to/authenticate-with-a-password.md +51 -0
  23. package/dist/docs/how-to/authenticate-with-an-api-key.md +51 -0
  24. package/dist/docs/how-to/authenticate-with-oauth.md +40 -0
  25. package/dist/docs/how-to/build-a-flow.md +83 -0
  26. package/dist/docs/how-to/connect-the-mcp-server.md +38 -0
  27. package/dist/docs/how-to/create-a-project.md +29 -0
  28. package/dist/docs/how-to/create-an-experience.md +42 -0
  29. package/dist/docs/how-to/create-and-revoke-an-api-key.md +37 -0
  30. package/dist/docs/how-to/debug-with-the-chrome-extension.md +57 -0
  31. package/dist/docs/how-to/define-a-page-layout.md +39 -0
  32. package/dist/docs/how-to/fill-and-publish-a-page.md +50 -0
  33. package/dist/docs/how-to/install-the-gtm-template.md +84 -0
  34. package/dist/docs/how-to/install-the-sdk.md +68 -0
  35. package/dist/docs/how-to/install-the-vite-plugin.md +56 -0
  36. package/dist/docs/how-to/invite-and-remove-members.md +34 -0
  37. package/dist/docs/how-to/preview-a-workspace.md +28 -0
  38. package/dist/docs/how-to/publish-a-workspace.md +30 -0
  39. package/dist/docs/how-to/read-a-feature-flag.md +101 -0
  40. package/dist/docs/how-to/register-a-component.md +55 -0
  41. package/dist/docs/how-to/register-an-action-handler.md +67 -0
  42. package/dist/docs/how-to/render-a-step-form.md +132 -0
  43. package/dist/docs/how-to/render-an-unpublished-preview.md +41 -0
  44. package/dist/docs/how-to/reuse-a-section.md +37 -0
  45. package/dist/docs/how-to/reuse-a-step-field-or-action.md +28 -0
  46. package/dist/docs/how-to/roll-back-a-published-version.md +26 -0
  47. package/dist/docs/how-to/run-an-ab-test.md +49 -0
  48. package/dist/docs/how-to/run-code-on-a-form-submission.md +125 -0
  49. package/dist/docs/how-to/server-render-a-page.md +81 -0
  50. package/dist/docs/how-to/set-a-content-security-policy.md +32 -0
  51. package/dist/docs/how-to/set-up-mfa.md +69 -0
  52. package/dist/docs/how-to/upload-and-use-an-asset.mdx +73 -0
  53. package/dist/docs/how-to/validate-a-field.md +52 -0
  54. package/dist/docs/how-to/write-a-condition.md +45 -0
  55. package/dist/docs/how-to/write-a-predicate.md +60 -0
  56. package/dist/docs/index.md +41 -59
  57. package/dist/docs/reference/dashboard/actions.mdx +53 -0
  58. package/dist/docs/reference/dashboard/api-keys.mdx +37 -0
  59. package/dist/docs/reference/dashboard/conditions.mdx +42 -0
  60. package/dist/docs/reference/dashboard/content/asset-library.mdx +63 -0
  61. package/dist/docs/reference/dashboard/content/content-entries.mdx +44 -0
  62. package/dist/docs/reference/dashboard/content/layouts.mdx +62 -0
  63. package/dist/docs/reference/dashboard/content/pages.mdx +35 -0
  64. package/dist/docs/reference/dashboard/content/sections.mdx +28 -0
  65. package/dist/docs/reference/dashboard/experiences.mdx +51 -0
  66. package/dist/docs/reference/dashboard/features.mdx +114 -0
  67. package/dist/docs/reference/dashboard/fields.mdx +100 -0
  68. package/dist/docs/reference/dashboard/flow-builder/canvas.mdx +58 -0
  69. package/dist/docs/reference/dashboard/flow-builder/condition-builder.md +57 -0
  70. package/dist/docs/reference/dashboard/flow-builder/keyboard-shortcuts.md +72 -0
  71. package/dist/docs/reference/dashboard/flow-builder/nodes.md +63 -0
  72. package/dist/docs/reference/dashboard/projects.mdx +44 -0
  73. package/dist/docs/reference/dashboard/reports.mdx +43 -0
  74. package/dist/docs/reference/dashboard/steps.mdx +37 -0
  75. package/dist/docs/reference/dashboard/team-management.md +29 -0
  76. package/dist/docs/reference/dashboard/workspace-versioning.mdx +30 -0
  77. package/dist/docs/reference/dashboard/workspaces.mdx +76 -0
  78. package/dist/docs/{delivery-api → reference/delivery-api}/experience-content.md +17 -5
  79. package/dist/docs/reference/delivery-api/index.md +45 -0
  80. package/dist/docs/reference/delivery-api/preview-caching-crawling.md +79 -0
  81. package/dist/docs/{delivery-api → reference/delivery-api}/project-config.md +15 -6
  82. package/dist/docs/reference/glossary.md +173 -0
  83. package/dist/docs/reference/management-api/authentication.md +74 -0
  84. package/dist/docs/{api → reference/management-api}/authorization-and-scopes.md +70 -47
  85. package/dist/docs/reference/management-api/error-handling.md +233 -0
  86. package/dist/docs/{api → reference/management-api}/pagination.md +36 -20
  87. package/dist/docs/reference/pickedql/data-sources.md +174 -0
  88. package/dist/docs/reference/pickedql/dimensions.md +87 -0
  89. package/dist/docs/{pickedql → reference/pickedql}/filtering.md +17 -6
  90. package/dist/docs/reference/pickedql/index.md +18 -0
  91. package/dist/docs/reference/pickedql/schema.md +172 -0
  92. package/dist/docs/reference/pickedql/virtual-functions.md +237 -0
  93. package/dist/docs/reference/sdk/actions.md +30 -0
  94. package/dist/docs/{sdk → reference/sdk}/conditions.md +15 -5
  95. package/dist/docs/reference/sdk/content-security-policy.md +21 -0
  96. package/dist/docs/reference/sdk/experiences.md +51 -0
  97. package/dist/docs/reference/sdk/features.md +233 -0
  98. package/dist/docs/reference/sdk/fields.md +209 -0
  99. package/dist/docs/reference/sdk/index.md +68 -0
  100. package/dist/docs/{sdk → reference/sdk}/plugins/create-experience.md +25 -34
  101. package/dist/docs/reference/sdk/plugins/dynamic-experiences.md +74 -0
  102. package/dist/docs/reference/sdk/plugins/index.md +29 -0
  103. package/dist/docs/{sdk → reference/sdk}/plugins/window-object.md +6 -0
  104. package/dist/docs/reference/sdk/predicates.md +43 -0
  105. package/dist/docs/reference/sdk/ssr/index.md +33 -0
  106. package/dist/docs/reference/sdk/ssr/rendering-and-hydration.md +103 -0
  107. package/dist/docs/reference/sdk/ssr/serialize.md +77 -0
  108. package/dist/docs/reference/sdk/ssr/slots-and-placements.md +59 -0
  109. package/dist/docs/reference/sdk/steps.md +87 -0
  110. package/dist/docs/reference/tools/chrome-extension.md +16 -0
  111. package/dist/docs/reference/tools/image-optimisation-service.md +104 -0
  112. package/dist/docs/reference/tools/mcp.md +88 -0
  113. package/dist/docs/reference/tools/vite-plugin.md +88 -0
  114. package/dist/docs/tutorials/first-api-call.md +228 -0
  115. package/dist/docs/tutorials/first-experience-in-the-dashboard.mdx +143 -0
  116. package/dist/docs/tutorials/first-experience.mdx +255 -0
  117. package/dist/docs/tutorials/first-server-rendered-page.mdx +186 -0
  118. package/dist/{dom-BwmTHeT7.js → dom-BqcToNL0.js} +1 -3
  119. package/dist/{dom-CDrHc_j9.cjs → dom-DlLH3FxV.cjs} +1 -1
  120. package/dist/esm/form/index.js +2 -4
  121. package/dist/esm/index.js +225 -186
  122. package/dist/esm/plugins/dom-observer/index.js +1 -1
  123. package/dist/esm/plugins/dynamic-experiences/index.js +3 -3
  124. package/dist/esm/preview/index.js +1 -1
  125. package/dist/esm/server/index.js +33 -31
  126. package/dist/{experience-instance-DOJShRk5.js → experience-instance-DGk11d8a.js} +3 -3
  127. package/dist/experience-instance-Dej3P1sE.cjs +1 -0
  128. package/dist/plugin-CHOVsx7Z.js +287 -0
  129. package/dist/plugin-DsaGXQHx.cjs +1 -0
  130. package/dist/{preview-channel-DW9J8t4B.js → preview-channel-CSr96XAo.js} +1 -1
  131. package/dist/{protocol-DSqOlW2r.js → protocol-C5KkkiZc.js} +1 -1
  132. package/dist/types/client.d.ts +7 -6
  133. package/dist/types/data-source/api.d.ts +60 -0
  134. package/dist/types/data-source/api.d.ts.map +1 -0
  135. package/dist/types/data-source/provider.d.ts +97 -0
  136. package/dist/types/data-source/provider.d.ts.map +1 -0
  137. package/dist/types/entities/action/action.d.ts +5 -4
  138. package/dist/types/entities/action/action.d.ts.map +1 -1
  139. package/dist/types/entities/component/component.d.ts +6 -5
  140. package/dist/types/entities/component/component.d.ts.map +1 -1
  141. package/dist/types/entities/condition/condition.d.ts +5 -5
  142. package/dist/types/entities/content/content.d.ts +4 -3
  143. package/dist/types/entities/experience/experience.d.ts +11 -10
  144. package/dist/types/entities/experience/experience.d.ts.map +1 -1
  145. package/dist/types/entities/experience-instance/experience-instance.d.ts +10 -9
  146. package/dist/types/entities/feature/feature.d.ts +19 -2
  147. package/dist/types/entities/feature/feature.d.ts.map +1 -1
  148. package/dist/types/entities/field/field.d.ts +7 -6
  149. package/dist/types/entities/framework/framework.d.ts +7 -6
  150. package/dist/types/entities/framework/framework.d.ts.map +1 -1
  151. package/dist/types/entities/history/history.d.ts +6 -6
  152. package/dist/types/entities/plugin/plugin.d.ts +3 -2
  153. package/dist/types/entities/plugin/plugin.d.ts.map +1 -1
  154. package/dist/types/entities/predicate/predicate.d.ts +4 -3
  155. package/dist/types/entities/predicate/predicate.d.ts.map +1 -1
  156. package/dist/types/entities/response/response-validation.d.ts +3 -2
  157. package/dist/types/entities/response/response.d.ts +12 -11
  158. package/dist/types/entities/session/session.d.ts +2 -1
  159. package/dist/types/entities/step/step.d.ts +6 -5
  160. package/dist/types/exports.d.ts +2 -1
  161. package/dist/types/exports.d.ts.map +1 -1
  162. package/dist/types/form/build-responses.d.ts +2 -1
  163. package/dist/types/form/create-field-evaluator.d.ts +4 -3
  164. package/dist/types/form/create-field-validation.d.ts +5 -4
  165. package/dist/types/form/create-form.d.ts +7 -6
  166. package/dist/types/form/create-submit-pipeline.d.ts +7 -6
  167. package/dist/types/form/get-step-fields.d.ts +3 -2
  168. package/dist/types/lifecycle/condition-selection.d.ts +14 -4
  169. package/dist/types/lifecycle/lifecycle.d.ts +4 -3
  170. package/dist/types/lifecycle/rules-logic.d.ts +4 -3
  171. package/dist/types/lifecycle/state-snapshot.d.ts +4 -3
  172. package/dist/types/picked.d.ts +79 -62
  173. package/dist/types/picked.d.ts.map +1 -1
  174. package/dist/types/ping.d.ts +1 -1
  175. package/dist/types/ping.d.ts.map +1 -1
  176. package/dist/types/plugins/create-experience/create-experience.d.ts +9 -8
  177. package/dist/types/plugins/create-experience/create-experience.d.ts.map +1 -1
  178. package/dist/types/plugins/create-experience/plugin.d.ts +3 -2
  179. package/dist/types/plugins/create-experience/plugin.d.ts.map +1 -1
  180. package/dist/types/plugins/create-experience/serialization.d.ts.map +1 -1
  181. package/dist/types/plugins/dom-observer/plugin.d.ts +1 -1
  182. package/dist/types/plugins/dynamic-experiences/hash.d.ts +40 -5
  183. package/dist/types/plugins/dynamic-experiences/hash.d.ts.map +1 -1
  184. package/dist/types/plugins/dynamic-experiences/index.d.ts +2 -0
  185. package/dist/types/plugins/dynamic-experiences/index.d.ts.map +1 -1
  186. package/dist/types/plugins/dynamic-experiences/plugin.d.ts +4 -36
  187. package/dist/types/plugins/dynamic-experiences/plugin.d.ts.map +1 -1
  188. package/dist/types/plugins/dynamic-experiences/types.d.ts +42 -11
  189. package/dist/types/plugins/dynamic-experiences/types.d.ts.map +1 -1
  190. package/dist/types/plugins/experience-browser-storage/plugin.d.ts +1 -1
  191. package/dist/types/plugins/experience-browser-storage/plugin.d.ts.map +1 -1
  192. package/dist/types/plugins/history-browser-storage/plugin.d.ts +1 -1
  193. package/dist/types/plugins/history-browser-storage/plugin.d.ts.map +1 -1
  194. package/dist/types/plugins/responses-browser-storage/plugin.d.ts +1 -1
  195. package/dist/types/plugins/responses-browser-storage/plugin.d.ts.map +1 -1
  196. package/dist/types/plugins/responses-indexeddb/plugin.d.ts +1 -1
  197. package/dist/types/plugins/single-page-app/plugin.d.ts +1 -1
  198. package/dist/types/plugins/single-page-app/plugin.d.ts.map +1 -1
  199. package/dist/types/plugins/web-components/plugin.d.ts +2 -1
  200. package/dist/types/plugins/window-object/plugin.d.ts +2 -2
  201. package/dist/types/preview-channel.d.ts +5 -1
  202. package/dist/types/preview-receiver/index.d.ts +18 -1
  203. package/dist/types/preview-receiver/protocol.d.ts +10 -1
  204. package/dist/types/server/index.d.ts +3 -3
  205. package/dist/types/server/serialize.d.ts +8 -2
  206. package/dist/types/server/serialize.d.ts.map +1 -1
  207. package/dist/types/utils/dom.d.ts +2 -1
  208. package/dist/types/utils/events.d.ts +6 -6
  209. package/dist/types/utils/events.d.ts.map +1 -1
  210. package/dist/types/utils/global-obj.d.ts +1 -1
  211. package/dist/types/utils/global-obj.d.ts.map +1 -1
  212. package/dist/types/utils/id.d.ts.map +1 -1
  213. package/dist/types/utils/logger.d.ts +2 -1
  214. package/dist/types/utils/logger.d.ts.map +1 -1
  215. package/dist/types/utils/node-tree/get-next-node-from-action.d.ts +2 -1
  216. package/dist/types/utils/node-tree/get-next-node-from-condition.d.ts +2 -1
  217. package/dist/types/utils/node-tree/get-next-node.d.ts +1 -1
  218. package/dist/types/utils/node-tree/get-next-node.d.ts.map +1 -1
  219. package/dist/types/utils/node-tree/get-origin-node.d.ts +1 -1
  220. package/dist/types/utils/node-tree/get-origin-node.d.ts.map +1 -1
  221. package/dist/types/utils/node-tree/min-max-steps-to-leaf.d.ts +1 -1
  222. package/dist/types/utils/node-tree/min-max-steps-to-leaf.d.ts.map +1 -1
  223. package/dist/types/utils/node-tree/min-max-steps-to-origin.d.ts +1 -1
  224. package/dist/types/utils/node-tree/min-max-steps-to-origin.d.ts.map +1 -1
  225. package/dist/types/utils/node-tree/next-reachable-step-nodes.d.ts +1 -1
  226. package/dist/types/utils/node-tree/next-reachable-step-nodes.d.ts.map +1 -1
  227. package/dist/types/utils/nodes.d.ts +1 -1
  228. package/dist/types/utils/picked-config.d.ts +2 -1
  229. package/dist/types/utils/rehydrate-scripts.d.ts +6 -0
  230. package/dist/types/utils/rehydrate-scripts.d.ts.map +1 -1
  231. package/dist/types/utils/rules-logic.d.ts +6 -2
  232. package/dist/types/utils/storage.d.ts +1 -1
  233. package/dist/types/utils/storage.d.ts.map +1 -1
  234. package/package.json +22 -23
  235. package/dist/api-CPL40b7A.js +0 -40
  236. package/dist/api-Dz5rgRgQ.cjs +0 -1
  237. package/dist/docs/actions.mdx +0 -78
  238. package/dist/docs/api/authentication.md +0 -376
  239. package/dist/docs/api/error-handling.md +0 -211
  240. package/dist/docs/api/index.md +0 -197
  241. package/dist/docs/api-keys.mdx +0 -40
  242. package/dist/docs/chrome-extension.md +0 -51
  243. package/dist/docs/conditions.mdx +0 -59
  244. package/dist/docs/content/asset-library.mdx +0 -93
  245. package/dist/docs/content/content-entries.mdx +0 -30
  246. package/dist/docs/content/layouts.mdx +0 -70
  247. package/dist/docs/content/pages.mdx +0 -67
  248. package/dist/docs/content/sections.mdx +0 -33
  249. package/dist/docs/delivery-api/index.md +0 -46
  250. package/dist/docs/delivery-api/preview-caching-crawling.md +0 -59
  251. package/dist/docs/experiences.mdx +0 -42
  252. package/dist/docs/features.mdx +0 -58
  253. package/dist/docs/fields.mdx +0 -79
  254. package/dist/docs/flow-builder/building-flows.md +0 -61
  255. package/dist/docs/flow-builder/condition-builder.md +0 -54
  256. package/dist/docs/flow-builder/keyboard-shortcuts.md +0 -66
  257. package/dist/docs/flow-builder/nodes.md +0 -43
  258. package/dist/docs/flow-builder/overview.mdx +0 -50
  259. package/dist/docs/gtm-template.md +0 -69
  260. package/dist/docs/guides/build-a-personalized-page.mdx +0 -143
  261. package/dist/docs/image-optimisation-service.md +0 -80
  262. package/dist/docs/mcp.md +0 -120
  263. package/dist/docs/pickedql/data-sources.md +0 -145
  264. package/dist/docs/pickedql/dimensions.md +0 -65
  265. package/dist/docs/pickedql/index.md +0 -36
  266. package/dist/docs/pickedql/schema.md +0 -156
  267. package/dist/docs/pickedql/virtual-functions.md +0 -204
  268. package/dist/docs/projects.mdx +0 -37
  269. package/dist/docs/reports.mdx +0 -18
  270. package/dist/docs/sdk/actions.md +0 -66
  271. package/dist/docs/sdk/content-security-policy.md +0 -32
  272. package/dist/docs/sdk/experiences.md +0 -46
  273. package/dist/docs/sdk/features.md +0 -212
  274. package/dist/docs/sdk/fields.md +0 -263
  275. package/dist/docs/sdk/index.md +0 -83
  276. package/dist/docs/sdk/plugins/dynamic-experiences.md +0 -58
  277. package/dist/docs/sdk/plugins/index.md +0 -9
  278. package/dist/docs/sdk/predicates.md +0 -112
  279. package/dist/docs/sdk/ssr/index.md +0 -62
  280. package/dist/docs/sdk/ssr/rendering-and-hydration.md +0 -141
  281. package/dist/docs/sdk/ssr/serialize.md +0 -86
  282. package/dist/docs/sdk/ssr/slots-and-placements.md +0 -35
  283. package/dist/docs/sdk/steps.md +0 -434
  284. package/dist/docs/steps.mdx +0 -44
  285. package/dist/docs/team-management.md +0 -40
  286. package/dist/docs/vite-plugin.md +0 -82
  287. package/dist/docs/workspace-versioning.mdx +0 -28
  288. package/dist/docs/workspaces.mdx +0 -102
  289. package/dist/experience-instance-DurC3pE-.cjs +0 -1
  290. package/dist/plugin-CFXwbXeM.js +0 -247
  291. package/dist/plugin-m4qekgtA.cjs +0 -1
@@ -1,14 +1,18 @@
1
1
  ---
2
+ type: reference
2
3
  layout: docs
3
4
  ---
4
5
 
5
6
  # Authorization and scopes
6
7
 
7
- The Picked API uses a scope-based authorization model. Every authenticated caller (session user or API key) carries a set of scopes that determine which operations they can perform. This guide explains the scope system, roles, and how permissions are resolved.
8
+ The Picked API controls access with scopes. Every authenticated caller carries a set
9
+ of scopes, and those scopes decide which operations the caller can do. A caller is
10
+ either a user with a session or an API key. This guide covers the scopes, the roles,
11
+ and how the API resolves a permission.
8
12
 
9
- ## Scope naming format
13
+ ## The format of a scope name
10
14
 
11
- Scopes follow the `entity/action` convention:
15
+ A scope has the form `resource/action`:
12
16
 
13
17
  ```
14
18
  organization/read
@@ -16,83 +20,87 @@ organization_members/create
16
20
  organization_projects/delete
17
21
  ```
18
22
 
19
- - **entity** — a lowercase name using underscores for multi-word entities (e.g., `organization_members`, `organization_api_keys`)
20
- - **action** — one of `create`, `read`, `update`, or `delete`
23
+ - **resource** — a lowercase name. It uses an underscore between words, as in
24
+ `organization_members` and `organization_api_keys`.
25
+ - **action** — one of `create`, `read`, `update`, or `delete`.
21
26
 
22
- In the GraphQL schema, scopes are represented as the `Scope` enum using uppercase with underscores (e.g., `ORGANIZATION_READ`, `ORGANIZATION_MEMBERS_CREATE`). Both formats refer to the same scope.
27
+ The GraphQL schema holds the scopes in the `Scope` enum. There they are uppercase
28
+ with an underscore between words, as in `ORGANIZATION_READ` and
29
+ `ORGANIZATION_MEMBERS_CREATE`. The two forms name the same scope.
23
30
 
24
31
  ## Full scope list
25
32
 
26
- The following scopes are available:
33
+ These are the scopes:
27
34
 
28
35
  ### Organization
29
36
 
30
37
  | Scope | GraphQL Enum | Description |
31
38
  |-------|-------------|-------------|
32
- | `organization/create` | `ORGANIZATION_CREATE` | Create new organizations |
33
- | `organization/read` | `ORGANIZATION_READ` | View organization details |
34
- | `organization/update` | `ORGANIZATION_UPDATE` | Update organization name, slug, and settings |
39
+ | `organization/create` | `ORGANIZATION_CREATE` | Create an organization |
40
+ | `organization/read` | `ORGANIZATION_READ` | Read the detail of an organization |
41
+ | `organization/update` | `ORGANIZATION_UPDATE` | Update the name, the slug, and the settings of an organization |
35
42
  | `organization/delete` | `ORGANIZATION_DELETE` | Delete an organization |
36
43
 
37
44
  ### Organization members
38
45
 
39
46
  | Scope | GraphQL Enum | Description |
40
47
  |-------|-------------|-------------|
41
- | `organization_members/create` | `ORGANIZATION_MEMBERS_CREATE` | Add members to an organization |
42
- | `organization_members/read` | `ORGANIZATION_MEMBERS_READ` | View organization member list |
43
- | `organization_members/update` | `ORGANIZATION_MEMBERS_UPDATE` | Update member roles |
44
- | `organization_members/delete` | `ORGANIZATION_MEMBERS_DELETE` | Remove members from an organization |
48
+ | `organization_members/create` | `ORGANIZATION_MEMBERS_CREATE` | Add a member to an organization |
49
+ | `organization_members/read` | `ORGANIZATION_MEMBERS_READ` | Read the member list of an organization |
50
+ | `organization_members/update` | `ORGANIZATION_MEMBERS_UPDATE` | Update the role of a member |
51
+ | `organization_members/delete` | `ORGANIZATION_MEMBERS_DELETE` | Remove a member from an organization |
45
52
 
46
53
  ### Organization invitations
47
54
 
48
55
  | Scope | GraphQL Enum | Description |
49
56
  |-------|-------------|-------------|
50
- | `organization_invitations/create` | `ORGANIZATION_INVITATIONS_CREATE` | Send invitations to join an organization |
51
- | `organization_invitations/read` | `ORGANIZATION_INVITATIONS_READ` | View pending invitations |
52
- | `organization_invitations/delete` | `ORGANIZATION_INVITATIONS_DELETE` | Revoke pending invitations |
57
+ | `organization_invitations/create` | `ORGANIZATION_INVITATIONS_CREATE` | Send an invitation to join an organization |
58
+ | `organization_invitations/read` | `ORGANIZATION_INVITATIONS_READ` | Read the invitations that wait for an answer |
59
+ | `organization_invitations/delete` | `ORGANIZATION_INVITATIONS_DELETE` | Revoke an invitation that waits for an answer |
53
60
 
54
61
  ### Organization projects
55
62
 
56
63
  | Scope | GraphQL Enum | Description |
57
64
  |-------|-------------|-------------|
58
- | `organization_projects/create` | `ORGANIZATION_PROJECTS_CREATE` | Create new projects |
59
- | `organization_projects/read` | `ORGANIZATION_PROJECTS_READ` | View project details |
60
- | `organization_projects/update` | `ORGANIZATION_PROJECTS_UPDATE` | Update project settings |
61
- | `organization_projects/delete` | `ORGANIZATION_PROJECTS_DELETE` | Delete projects |
65
+ | `organization_projects/create` | `ORGANIZATION_PROJECTS_CREATE` | Create a project |
66
+ | `organization_projects/read` | `ORGANIZATION_PROJECTS_READ` | Read the detail of a project |
67
+ | `organization_projects/update` | `ORGANIZATION_PROJECTS_UPDATE` | Update the settings of a project |
68
+ | `organization_projects/delete` | `ORGANIZATION_PROJECTS_DELETE` | Delete a project |
62
69
 
63
70
  ### Organization API keys
64
71
 
65
72
  | Scope | GraphQL Enum | Description |
66
73
  |-------|-------------|-------------|
67
- | `organization_api_keys/create` | `ORGANIZATION_API_KEYS_CREATE` | Create new API keys |
68
- | `organization_api_keys/read` | `ORGANIZATION_API_KEYS_READ` | View API keys (prefix only, not the full key) |
69
- | `organization_api_keys/delete` | `ORGANIZATION_API_KEYS_DELETE` | Revoke API keys |
74
+ | `organization_api_keys/create` | `ORGANIZATION_API_KEYS_CREATE` | Create an API key |
75
+ | `organization_api_keys/read` | `ORGANIZATION_API_KEYS_READ` | Read the API keys. This gives the prefix only, and not the full key. |
76
+ | `organization_api_keys/delete` | `ORGANIZATION_API_KEYS_DELETE` | Revoke an API key |
70
77
 
71
78
  ### Organization integrations
72
79
 
73
80
  | Scope | GraphQL Enum | Description |
74
81
  |-------|-------------|-------------|
75
- | `organization_integrations/create` | `ORGANIZATION_INTEGRATIONS_CREATE` | Set up new integrations |
76
- | `organization_integrations/read` | `ORGANIZATION_INTEGRATIONS_READ` | View integration configurations |
77
- | `organization_integrations/update` | `ORGANIZATION_INTEGRATIONS_UPDATE` | Modify integration settings |
78
- | `organization_integrations/delete` | `ORGANIZATION_INTEGRATIONS_DELETE` | Remove integrations |
82
+ | `organization_integrations/create` | `ORGANIZATION_INTEGRATIONS_CREATE` | Set up an integration |
83
+ | `organization_integrations/read` | `ORGANIZATION_INTEGRATIONS_READ` | Read the options of an integration |
84
+ | `organization_integrations/update` | `ORGANIZATION_INTEGRATIONS_UPDATE` | Change the settings of an integration |
85
+ | `organization_integrations/delete` | `ORGANIZATION_INTEGRATIONS_DELETE` | Remove an integration |
79
86
 
80
87
  ### Organization reports
81
88
 
82
89
  | Scope | GraphQL Enum | Description |
83
90
  |-------|-------------|-------------|
84
- | `organization_reports/create` | `ORGANIZATION_REPORTS_CREATE` | Create new reports |
85
- | `organization_reports/read` | `ORGANIZATION_REPORTS_READ` | View reports |
86
- | `organization_reports/update` | `ORGANIZATION_REPORTS_UPDATE` | Update report settings |
87
- | `organization_reports/delete` | `ORGANIZATION_REPORTS_DELETE` | Delete reports |
91
+ | `organization_reports/create` | `ORGANIZATION_REPORTS_CREATE` | Create a report |
92
+ | `organization_reports/read` | `ORGANIZATION_REPORTS_READ` | Read a report |
93
+ | `organization_reports/update` | `ORGANIZATION_REPORTS_UPDATE` | Update the settings of a report |
94
+ | `organization_reports/delete` | `ORGANIZATION_REPORTS_DELETE` | Delete a report |
88
95
 
89
96
  ## Roles
90
97
 
91
- Organization members are assigned one of two roles:
98
+ Each member of an organization holds one of two roles:
92
99
 
93
100
  ### Owner
94
101
 
95
- Owners have full control within their organization. Their default scopes include:
102
+ An owner has full control inside the organization. These are the default scopes of an
103
+ owner:
96
104
 
97
105
  - All `organization/*` scopes (`read`, `update`, `delete`)
98
106
  - All `organization_members/*` scopes
@@ -104,7 +112,8 @@ Owners have full control within their organization. Their default scopes include
104
112
 
105
113
  ### Member
106
114
 
107
- Members have broad access but cannot delete the organization or manage other members. Their default scopes include:
115
+ A member can reach most things, but cannot delete the organization and cannot control
116
+ another member. These are the default scopes of a member:
108
117
 
109
118
  - `organization/read`, `organization/update`
110
119
  - `organization_members/read`
@@ -114,7 +123,7 @@ Members have broad access but cannot delete the organization or manage other mem
114
123
  - All `organization_integrations/*` scopes
115
124
  - `organization_reports/read`
116
125
 
117
- The key differences between owner and member:
126
+ These are the differences between an owner and a member:
118
127
 
119
128
  | Capability | Owner | Member |
120
129
  |-----------|-------|--------|
@@ -123,24 +132,30 @@ The key differences between owner and member:
123
132
  | Remove members | Yes | No |
124
133
  | Update member roles | Yes | No |
125
134
  | Revoke invitations | Yes | No |
126
- | Manage projects and integrations | Yes | Yes |
127
- | Manage API keys | Yes | Yes |
128
- | View reports | Yes | Yes |
135
+ | Control projects and integrations | Yes | Yes |
136
+ | Control API keys | Yes | Yes |
137
+ | Read reports | Yes | Yes |
129
138
 
130
139
  ## How scopes are resolved
131
140
 
132
- When an authenticated request reaches the API, the authorization system resolves scopes as follows:
141
+ When an authenticated request reaches the API, the API resolves the scopes like this:
133
142
 
134
- 1. **Session-authenticated users** — the API looks up the caller's role within the target organization and assigns the default scopes for that role.
135
- 2. **API key requests** — the API uses the scopes that were assigned to the key at creation time. These scopes are always a subset of the creating user's scopes.
143
+ 1. **A user with a session** — the API finds the role of that caller in the target
144
+ organization. It then gives the caller the default scopes of that role.
145
+ 2. **A request with an API key** — the API uses the scopes that the key received when
146
+ somebody created it. Those scopes are always scopes of the user who created the
147
+ key.
136
148
 
137
- For operations that target a specific organization (most queries and mutations), the caller must have the required scope within that organization. For root-level operations like `organizationCreate`, the scope is resolved at the account level.
149
+ Most queries and mutations point at one organization. For those, the caller must hold
150
+ the scope inside that organization. For a root-level operation such as
151
+ `organizationCreate`, the API resolves the scope at the account level.
138
152
 
139
- If the caller lacks the required scope, the API returns an authorization error with a `FORBIDDEN` code. See [Error Handling](./error-handling.md) for details.
153
+ When the caller does not hold the scope that an operation needs, the API returns an
154
+ authorization error with the code `FORBIDDEN`. See [Errors](/reference/management-api/error-handling).
140
155
 
141
156
  ## Operations and required scopes
142
157
 
143
- The following table maps common operations to the scopes they require:
158
+ This table gives the scope that each common operation needs:
144
159
 
145
160
  ### Queries
146
161
 
@@ -192,7 +207,7 @@ Some mutations do not require organization-level scopes because they operate on
192
207
  | `organizationInvitationAccept` / `organizationInvitationDecline` | Authenticated session (no specific scope) |
193
208
  | `mfaFactorEnroll` / `mfaChallengeSend` / `mfaChallengeVerify` / `mfaFactorUnenroll` | Authenticated session (no specific scope) |
194
209
 
195
- ## Querying scopes
210
+ ## Read your scopes
196
211
 
197
212
  ### Root-level scopes
198
213
 
@@ -259,4 +274,12 @@ Response:
259
274
  }
260
275
  ```
261
276
 
262
- This is useful for building UIs that adapt based on the caller's permissions — for example, hiding a "Delete Organization" button when the caller lacks `ORGANIZATION_DELETE`.
277
+ Use this to build a UI that changes with the permissions of the caller. An example is
278
+ a **Delete Organization** button that the UI hides when the caller does not hold
279
+ `ORGANIZATION_DELETE`.
280
+
281
+ ## Related
282
+
283
+ - [Authentication](/reference/management-api/authentication)
284
+ - [How to authenticate with an API key](/how-to/authenticate-with-an-api-key)
285
+ - [API keys](/reference/dashboard/api-keys) — the dashboard surface.
@@ -0,0 +1,233 @@
1
+ ---
2
+ type: reference
3
+ layout: docs
4
+ ---
5
+
6
+ # Errors
7
+
8
+ The Picked API returns an error in the standard GraphQL format. This guide covers the
9
+ shape of an error response, every error code, and what your code must do with each
10
+ one.
11
+
12
+ ## Error response shape
13
+
14
+ When an operation fails, the API returns an `errors` array in the response body. Each
15
+ error object holds these fields:
16
+
17
+ ```json
18
+ {
19
+ "data": null,
20
+ "errors": [
21
+ {
22
+ "message": "A human-readable description of the error",
23
+ "path": ["mutationName"],
24
+ "extensions": {
25
+ "code": "ERROR_CODE"
26
+ }
27
+ }
28
+ ]
29
+ }
30
+ ```
31
+
32
+ | Field | Description |
33
+ |-------|-------------|
34
+ | `message` | A description of the error that a person can read. Put it in your log. Do not write code against it. |
35
+ | `path` | The path to the field in the query that made the error. |
36
+ | `extensions.code` | An error code that a machine can read. Write your code against this field. |
37
+
38
+ One response can hold more than one error. The `data` field is `null` when the whole
39
+ operation failed. It holds part of the data when only some fields failed.
40
+
41
+ ## Authentication error codes
42
+
43
+ These errors come from a session, an account, OAuth, a magic link, a password
44
+ operation, or MFA. They match the `AuthErrorCode` enum in the schema.
45
+
46
+ | Code | Description |
47
+ |------|-------------|
48
+ | `INVALID_CREDENTIALS` | The email address and the password do not match. |
49
+ | `EMAIL_NOT_CONFIRMED` | The account is there, but nobody verified the email address. See [Authentication](/reference/management-api/authentication#verify-an-email-address). |
50
+ | `USER_NOT_FOUND` | There is no account with that email address. |
51
+ | `USER_ALREADY_EXISTS` | An account with that email address is there already. The API returns this when you create an account. |
52
+ | `WEAK_PASSWORD` | The password is not strong enough. |
53
+ | `INVALID_TOKEN` | The token is invalid or malformed. This covers a verification token, a reset token, and a magic link token. |
54
+ | `TOKEN_EXPIRED` | The token expired. Ask for a new one. |
55
+ | `MFA_CHALLENGE_FAILED` | The MFA verification code is not correct. |
56
+ | `MFA_FACTOR_NOT_FOUND` | That MFA factor is not there, or it belongs to another caller. |
57
+ | `OAUTH_PROVIDER_ERROR` | The exchange with the OAuth provider, such as Google, failed. |
58
+ | `RATE_LIMITED` | Too many requests in a short period. Wait, then try again. |
59
+
60
+ ### Example: invalid credentials
61
+
62
+ ```json
63
+ {
64
+ "data": {
65
+ "sessionCreate": {
66
+ "session": null,
67
+ "requiresMfa": false,
68
+ "mfaFactors": null
69
+ }
70
+ },
71
+ "errors": [
72
+ {
73
+ "message": "Invalid credentials",
74
+ "path": ["sessionCreate"],
75
+ "extensions": {
76
+ "code": "INVALID_CREDENTIALS"
77
+ }
78
+ }
79
+ ]
80
+ }
81
+ ```
82
+
83
+ ## Authorization error codes
84
+
85
+ An authorization error happens when the caller does not hold the
86
+ [scope](/reference/management-api/authorization-and-scopes) that an operation needs.
87
+
88
+ | Code | Description |
89
+ |------|-------------|
90
+ | `UNAUTHORIZED` | The request carries no valid authentication. It has no `Authorization` header and no `x-api-key` header, or the token is invalid. |
91
+ | `FORBIDDEN` | The caller is authenticated, but it does not hold the scope that the operation needs. |
92
+
93
+ ### Example: the scope is not enough
94
+
95
+ A caller that holds `organization/read` only tries to delete an organization. It
96
+ receives this:
97
+
98
+ ```json
99
+ {
100
+ "data": {
101
+ "organizationDelete": null
102
+ },
103
+ "errors": [
104
+ {
105
+ "message": "Insufficient permissions",
106
+ "path": ["organizationDelete"],
107
+ "extensions": {
108
+ "code": "FORBIDDEN"
109
+ }
110
+ }
111
+ ]
112
+ }
113
+ ```
114
+
115
+ ## Organization, member, and invitation error codes
116
+
117
+ These errors come from an organization, a member operation, or an invitation. They
118
+ match the `ErrorCode` enum in the schema.
119
+
120
+ ### Organization errors
121
+
122
+ | Code | Description |
123
+ |------|-------------|
124
+ | `ORGANIZATION_NOT_FOUND` | That organization is not there, or the caller cannot reach it. |
125
+ | `ORGANIZATION_ALREADY_EXISTS` | An organization with that name is there already. |
126
+ | `SLUG_ALREADY_EXISTS` | Another organization uses that slug already. |
127
+ | `INVALID_SLUG` | The slug holds an invalid character. A slug takes lowercase letters, digits, and hyphens only. |
128
+
129
+ ### Member errors
130
+
131
+ | Code | Description |
132
+ |------|-------------|
133
+ | `MEMBER_NOT_FOUND` | That user is not a member of the organization. |
134
+ | `MEMBER_ALREADY_EXISTS` | The user is a member of the organization already. |
135
+ | `CANNOT_REMOVE_PRIMARY_OWNER` | You cannot remove the primary owner of an organization. |
136
+ | `CANNOT_CHANGE_OWN_ROLE` | A member cannot change the role of that same member. Another owner must do it. |
137
+
138
+ ### Invitation errors
139
+
140
+ | Code | Description |
141
+ |------|-------------|
142
+ | `INVITATION_NOT_FOUND` | That invitation is not there. |
143
+ | `INVITATION_EXPIRED` | The invitation expired. Nobody can accept it now. |
144
+ | `INVITATION_ALREADY_ACCEPTED` | Somebody accepted the invitation already. |
145
+
146
+ ### Project errors
147
+
148
+ | Code | Description |
149
+ |------|-------------|
150
+ | `PROJECT_NOT_FOUND` | That project is not there, or the caller cannot reach it. |
151
+
152
+ ### General errors
153
+
154
+ | Code | Description |
155
+ |------|-------------|
156
+ | `VALIDATION_ERROR` | The input failed a validation rule. Read the `message` field to learn which field is invalid. |
157
+ | `INTERNAL_ERROR` | The server met an unexpected error. Try the request again. Contact support when the error continues. |
158
+
159
+ ## What your code must do
160
+
161
+ ### Look for an error first
162
+
163
+ Check every response for an `errors` array before you read `data`:
164
+
165
+ ```javascript
166
+ const response = await fetch('/graphql', {
167
+ method: 'POST',
168
+ headers: {
169
+ 'Content-Type': 'application/json',
170
+ 'Authorization': `Bearer ${accessToken}`,
171
+ },
172
+ body: JSON.stringify({ query, variables }),
173
+ });
174
+
175
+ const result = await response.json();
176
+
177
+ if (result.errors) {
178
+ for (const error of result.errors) {
179
+ const code = error.extensions?.code;
180
+
181
+ switch (code) {
182
+ case 'UNAUTHORIZED':
183
+ // Send the user to the sign-in page.
184
+ break;
185
+ case 'FORBIDDEN':
186
+ // Show a permissions error.
187
+ break;
188
+ case 'RATE_LIMITED':
189
+ // Wait, then try again.
190
+ break;
191
+ default:
192
+ // Put the message in the log, or show it.
193
+ console.error(error.message);
194
+ }
195
+ }
196
+ }
197
+ ```
198
+
199
+ ### Refresh a token that expired
200
+
201
+ A request can return `UNAUTHORIZED` while the caller holds a refresh token. Try a
202
+ [session refresh](/reference/management-api/authentication#refresh-a-session) first. Do not treat it as a
203
+ failure to sign in:
204
+
205
+ ```javascript
206
+ if (code === 'UNAUTHORIZED' && refreshToken) {
207
+ const refreshResult = await sessionRefresh(refreshToken);
208
+ if (refreshResult.session) {
209
+ // Try the first request again with the new access token.
210
+ } else {
211
+ // Send the user to the sign-in page.
212
+ }
213
+ }
214
+ ```
215
+
216
+ ### Read data that is only part complete
217
+
218
+ GraphQL can return part of the data together with an error. Take a query that reads
219
+ an organization and its members. It can succeed for the organization and fail for the
220
+ members, when the caller does not hold `organization_members/read`. The response then
221
+ holds `data` with the organization, and `errors` for the members field. Always read
222
+ both.
223
+
224
+ ### Try again after a transient failure
225
+
226
+ `INTERNAL_ERROR` and `RATE_LIMITED` are both transient. For `RATE_LIMITED`, use an
227
+ exponential backoff before you try again. For `INTERNAL_ERROR`, one more try is
228
+ usually enough.
229
+
230
+ ## Related
231
+
232
+ - [Authentication](/reference/management-api/authentication)
233
+ - [Your first API call](/tutorials/first-api-call)
@@ -1,14 +1,17 @@
1
1
  ---
2
+ type: reference
2
3
  layout: docs
3
4
  ---
4
5
 
5
6
  # Pagination
6
7
 
7
- The Picked API uses Relay-style cursor-based pagination for all list fields that may return large result sets. This guide explains the connection pattern and demonstrates how to paginate through results.
8
+ The Picked API paginates every list field that can return a large result. It uses a
9
+ cursor, in the Relay-style pattern. This guide covers the connection pattern and
10
+ shows how to move through a result.
8
11
 
9
12
  ## Connection pattern
10
13
 
11
- Paginated fields return a **connection** object with the following shape:
14
+ A paginated field returns a **connection** object with this shape:
12
15
 
13
16
  ```graphql
14
17
  type ExampleConnection {
@@ -32,20 +35,21 @@ type PageInfo {
32
35
 
33
36
  | Field | Description |
34
37
  |-------|-------------|
35
- | `edges` | An ordered list of edges, each containing a `cursor` and a `node` (the actual data object) |
36
- | `pageInfo.hasNextPage` | `true` if more results exist after the last edge |
37
- | `pageInfo.hasPreviousPage` | `true` if results exist before the first edge |
38
- | `pageInfo.startCursor` | Cursor of the first edge in the current page |
39
- | `pageInfo.endCursor` | Cursor of the last edge in the current page |
40
- | `totalCount` | Total number of items across all pages |
38
+ | `edges` | An ordered list of edges. Each edge holds a `cursor` and a `node`, and the `node` holds the data. |
39
+ | `pageInfo.hasNextPage` | `true` when more results come after the last edge |
40
+ | `pageInfo.hasPreviousPage` | `true` when results come before the first edge |
41
+ | `pageInfo.startCursor` | The cursor of the first edge on the current page |
42
+ | `pageInfo.endCursor` | The cursor of the last edge on the current page |
43
+ | `totalCount` | The number of items on every page together |
41
44
 
42
45
  ## Forward pagination with `first` and `after`
43
46
 
44
- To paginate forward through results, use the `first` argument to specify the page size and the `after` argument to specify the cursor to start after.
47
+ To move forward through the results, use two arguments. The `first` argument gives
48
+ the page size. The `after` argument gives the cursor to start after.
45
49
 
46
50
  ### First page
47
51
 
48
- Omit the `after` argument to fetch the first page:
52
+ Leave the `after` argument out to read the first page:
49
53
 
50
54
  ```graphql
51
55
  query {
@@ -89,16 +93,17 @@ query {
89
93
  }
90
94
  ```
91
95
 
92
- ## Checking for more pages
96
+ ## Check for more pages
93
97
 
94
- Before requesting the next page, check the `hasNextPage` field:
98
+ Read the `hasNextPage` field before you ask for the next page:
95
99
 
96
- - `hasNextPage: true` — more results are available; pass `endCursor` to the next request's `after` argument
97
- - `hasNextPage: false` — all results have been fetched; stop paginating
100
+ - `hasNextPage: true` — more results are available. Pass `endCursor` as the `after`
101
+ argument of the next request.
102
+ - `hasNextPage: false` — you read every result. Stop here.
98
103
 
99
104
  ## Full paginated query example
100
105
 
101
- The following example fetches all members of an organization, page by page:
106
+ This example reads every member of an organization, one page at a time:
102
107
 
103
108
  ```graphql
104
109
  # Page 1
@@ -154,7 +159,8 @@ Continue until `hasNextPage` returns `false`.
154
159
 
155
160
  ## Paginated fields
156
161
 
157
- The following fields in the schema return connection types and support `first`/`after` pagination:
162
+ These fields in the schema return a connection type. They all take the `first` and
163
+ `after` arguments:
158
164
 
159
165
  | Parent Type | Field | Connection Type |
160
166
  |------------|-------|----------------|
@@ -170,7 +176,17 @@ All of these fields accept the same `first` and `after` arguments and return the
170
176
 
171
177
  ## Tips
172
178
 
173
- - **Default page size** — if `first` is omitted, the API applies a default limit. Explicitly setting `first` ensures predictable page sizes.
174
- - **Cursors are opaque** — cursor strings should be treated as opaque tokens. Do not parse, construct, or modify them. Pass them exactly as received from the API.
175
- - **Stable ordering** — results within a connection are returned in a stable order. The same cursor always refers to the same position in the result set.
176
- - **Combine with other fields** — pagination arguments can be used alongside other query fields. For example, fetching an organization and its first page of members in a single request is common and efficient.
179
+ - **The default page size** — the API applies a default limit when you leave `first`
180
+ out. Set `first` yourself to make sure that each page has the size you expect.
181
+ - **A cursor is opaque** — treat a cursor string as an opaque token. Do not parse it,
182
+ build it, or change it. Pass it back exactly as the API gave it.
183
+ - **The order is stable** — a connection returns its results in a stable order. The
184
+ same cursor always points at the same position in the result.
185
+ - **Use them with other fields** — you can use the pagination arguments together with
186
+ other query fields. One request that reads an organization and the first page of
187
+ its members is common, and it is efficient.
188
+
189
+ ## Related
190
+
191
+ - [Your first API call](/tutorials/first-api-call)
192
+ - [Authorization and scopes](/reference/management-api/authorization-and-scopes)