@picked/client 0.0.70-next.6 → 0.0.71-next.1

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 (177) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/api-CH2FNa6S.cjs +1 -0
  3. package/dist/api-CgqRvuKL.js +38 -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/actions.mdx +38 -18
  10. package/dist/docs/api/authentication.md +75 -48
  11. package/dist/docs/api/authorization-and-scopes.md +63 -47
  12. package/dist/docs/api/error-handling.md +70 -54
  13. package/dist/docs/api/index.md +41 -22
  14. package/dist/docs/api/pagination.md +30 -20
  15. package/dist/docs/api-keys.mdx +11 -6
  16. package/dist/docs/chrome-extension.md +22 -5
  17. package/dist/docs/conditions.mdx +32 -19
  18. package/dist/docs/content/asset-library.mdx +65 -34
  19. package/dist/docs/content/content-entries.mdx +8 -2
  20. package/dist/docs/content/layouts.mdx +45 -29
  21. package/dist/docs/content/pages.mdx +29 -14
  22. package/dist/docs/content/sections.mdx +19 -8
  23. package/dist/docs/delivery-api/experience-content.md +10 -5
  24. package/dist/docs/delivery-api/index.md +19 -12
  25. package/dist/docs/delivery-api/preview-caching-crawling.md +27 -14
  26. package/dist/docs/delivery-api/project-config.md +6 -4
  27. package/dist/docs/experiences.mdx +26 -10
  28. package/dist/docs/features.mdx +66 -25
  29. package/dist/docs/fields.mdx +42 -27
  30. package/dist/docs/flow-builder/building-flows.md +38 -20
  31. package/dist/docs/flow-builder/condition-builder.md +32 -21
  32. package/dist/docs/flow-builder/keyboard-shortcuts.md +18 -18
  33. package/dist/docs/flow-builder/nodes.md +26 -13
  34. package/dist/docs/flow-builder/overview.mdx +28 -15
  35. package/dist/docs/gtm-template.md +35 -26
  36. package/dist/docs/guides/build-a-personalized-page.mdx +36 -18
  37. package/dist/docs/image-optimisation-service.md +33 -17
  38. package/dist/docs/index.md +28 -17
  39. package/dist/docs/mcp.md +46 -38
  40. package/dist/docs/pickedql/data-sources.md +65 -43
  41. package/dist/docs/pickedql/dimensions.md +27 -12
  42. package/dist/docs/pickedql/examples.md +38 -26
  43. package/dist/docs/pickedql/filtering.md +10 -6
  44. package/dist/docs/pickedql/index.md +32 -14
  45. package/dist/docs/pickedql/schema.md +85 -76
  46. package/dist/docs/pickedql/virtual-functions.md +62 -36
  47. package/dist/docs/projects.mdx +14 -7
  48. package/dist/docs/reports.mdx +5 -3
  49. package/dist/docs/sdk/actions.md +33 -17
  50. package/dist/docs/sdk/conditions.md +8 -5
  51. package/dist/docs/sdk/content-security-policy.md +5 -4
  52. package/dist/docs/sdk/experiences.md +29 -11
  53. package/dist/docs/sdk/feature-allocation.md +79 -47
  54. package/dist/docs/sdk/features.md +130 -76
  55. package/dist/docs/sdk/fields.md +66 -42
  56. package/dist/docs/sdk/index.md +22 -13
  57. package/dist/docs/sdk/plugins/create-experience.md +18 -15
  58. package/dist/docs/sdk/plugins/dynamic-experiences.md +42 -16
  59. package/dist/docs/sdk/predicates.md +53 -37
  60. package/dist/docs/sdk/ssr/index.md +25 -8
  61. package/dist/docs/sdk/ssr/rendering-and-hydration.md +37 -16
  62. package/dist/docs/sdk/ssr/serialize.md +38 -20
  63. package/dist/docs/sdk/ssr/slots-and-placements.md +28 -10
  64. package/dist/docs/sdk/steps.md +100 -55
  65. package/dist/docs/steps.mdx +20 -11
  66. package/dist/docs/team-management.md +17 -11
  67. package/dist/docs/vite-plugin.md +26 -19
  68. package/dist/docs/workspace-versioning.mdx +14 -8
  69. package/dist/docs/workspaces.mdx +55 -24
  70. package/dist/{dom-BwmTHeT7.js → dom-BqcToNL0.js} +1 -3
  71. package/dist/{dom-CDrHc_j9.cjs → dom-DlLH3FxV.cjs} +1 -1
  72. package/dist/esm/form/index.js +2 -4
  73. package/dist/esm/index.js +50 -45
  74. package/dist/esm/plugins/dom-observer/index.js +1 -1
  75. package/dist/esm/plugins/dynamic-experiences/index.js +2 -2
  76. package/dist/esm/preview/index.js +1 -1
  77. package/dist/esm/server/index.js +12 -10
  78. package/dist/{experience-instance-DOJShRk5.js → experience-instance-DGk11d8a.js} +3 -3
  79. package/dist/experience-instance-Dej3P1sE.cjs +1 -0
  80. package/dist/{plugin-BxMR7fOV.js → plugin-D2UqFikQ.js} +2 -2
  81. package/dist/plugin-DCW-tnjO.cjs +1 -0
  82. package/dist/{preview-channel-DW9J8t4B.js → preview-channel-CSr96XAo.js} +1 -1
  83. package/dist/{protocol-DSqOlW2r.js → protocol-C5KkkiZc.js} +1 -1
  84. package/dist/types/client.d.ts +7 -6
  85. package/dist/types/entities/action/action.d.ts +5 -4
  86. package/dist/types/entities/action/action.d.ts.map +1 -1
  87. package/dist/types/entities/component/component.d.ts +6 -5
  88. package/dist/types/entities/component/component.d.ts.map +1 -1
  89. package/dist/types/entities/condition/condition.d.ts +5 -5
  90. package/dist/types/entities/content/content.d.ts +4 -3
  91. package/dist/types/entities/experience/experience.d.ts +11 -10
  92. package/dist/types/entities/experience/experience.d.ts.map +1 -1
  93. package/dist/types/entities/experience-instance/experience-instance.d.ts +10 -9
  94. package/dist/types/entities/feature/feature.d.ts +3 -2
  95. package/dist/types/entities/feature/feature.d.ts.map +1 -1
  96. package/dist/types/entities/field/field.d.ts +7 -6
  97. package/dist/types/entities/framework/framework.d.ts +7 -6
  98. package/dist/types/entities/framework/framework.d.ts.map +1 -1
  99. package/dist/types/entities/history/history.d.ts +6 -6
  100. package/dist/types/entities/plugin/plugin.d.ts +3 -2
  101. package/dist/types/entities/plugin/plugin.d.ts.map +1 -1
  102. package/dist/types/entities/predicate/predicate.d.ts +4 -3
  103. package/dist/types/entities/predicate/predicate.d.ts.map +1 -1
  104. package/dist/types/entities/response/response-validation.d.ts +3 -2
  105. package/dist/types/entities/response/response.d.ts +12 -11
  106. package/dist/types/entities/session/session.d.ts +2 -1
  107. package/dist/types/entities/step/step.d.ts +6 -5
  108. package/dist/types/exports.d.ts +2 -1
  109. package/dist/types/exports.d.ts.map +1 -1
  110. package/dist/types/form/build-responses.d.ts +2 -1
  111. package/dist/types/form/create-field-evaluator.d.ts +4 -3
  112. package/dist/types/form/create-field-validation.d.ts +5 -4
  113. package/dist/types/form/create-form.d.ts +7 -6
  114. package/dist/types/form/create-submit-pipeline.d.ts +7 -6
  115. package/dist/types/form/get-step-fields.d.ts +3 -2
  116. package/dist/types/lifecycle/condition-selection.d.ts +14 -4
  117. package/dist/types/lifecycle/lifecycle.d.ts +4 -3
  118. package/dist/types/lifecycle/rules-logic.d.ts +4 -3
  119. package/dist/types/lifecycle/state-snapshot.d.ts +4 -3
  120. package/dist/types/picked.d.ts +64 -62
  121. package/dist/types/picked.d.ts.map +1 -1
  122. package/dist/types/ping.d.ts +1 -1
  123. package/dist/types/ping.d.ts.map +1 -1
  124. package/dist/types/plugins/create-experience/create-experience.d.ts +9 -8
  125. package/dist/types/plugins/create-experience/create-experience.d.ts.map +1 -1
  126. package/dist/types/plugins/create-experience/plugin.d.ts +3 -2
  127. package/dist/types/plugins/create-experience/plugin.d.ts.map +1 -1
  128. package/dist/types/plugins/create-experience/serialization.d.ts.map +1 -1
  129. package/dist/types/plugins/dom-observer/plugin.d.ts +1 -1
  130. package/dist/types/plugins/dynamic-experiences/plugin.d.ts +3 -3
  131. package/dist/types/plugins/dynamic-experiences/types.d.ts +8 -5
  132. package/dist/types/plugins/experience-browser-storage/plugin.d.ts +1 -1
  133. package/dist/types/plugins/experience-browser-storage/plugin.d.ts.map +1 -1
  134. package/dist/types/plugins/history-browser-storage/plugin.d.ts +1 -1
  135. package/dist/types/plugins/history-browser-storage/plugin.d.ts.map +1 -1
  136. package/dist/types/plugins/responses-browser-storage/plugin.d.ts +1 -1
  137. package/dist/types/plugins/responses-browser-storage/plugin.d.ts.map +1 -1
  138. package/dist/types/plugins/responses-indexeddb/plugin.d.ts +1 -1
  139. package/dist/types/plugins/single-page-app/plugin.d.ts +1 -1
  140. package/dist/types/plugins/single-page-app/plugin.d.ts.map +1 -1
  141. package/dist/types/plugins/web-components/plugin.d.ts +2 -1
  142. package/dist/types/plugins/window-object/plugin.d.ts +2 -2
  143. package/dist/types/preview-channel.d.ts +5 -1
  144. package/dist/types/preview-receiver/index.d.ts +18 -1
  145. package/dist/types/preview-receiver/protocol.d.ts +10 -1
  146. package/dist/types/server/index.d.ts +3 -3
  147. package/dist/types/server/serialize.d.ts +2 -2
  148. package/dist/types/utils/dom.d.ts +2 -1
  149. package/dist/types/utils/events.d.ts +6 -6
  150. package/dist/types/utils/events.d.ts.map +1 -1
  151. package/dist/types/utils/global-obj.d.ts +1 -1
  152. package/dist/types/utils/global-obj.d.ts.map +1 -1
  153. package/dist/types/utils/id.d.ts.map +1 -1
  154. package/dist/types/utils/logger.d.ts +2 -1
  155. package/dist/types/utils/logger.d.ts.map +1 -1
  156. package/dist/types/utils/node-tree/get-next-node-from-action.d.ts +2 -1
  157. package/dist/types/utils/node-tree/get-next-node-from-condition.d.ts +2 -1
  158. package/dist/types/utils/node-tree/get-next-node.d.ts +1 -1
  159. package/dist/types/utils/node-tree/get-next-node.d.ts.map +1 -1
  160. package/dist/types/utils/node-tree/get-origin-node.d.ts +1 -1
  161. package/dist/types/utils/node-tree/get-origin-node.d.ts.map +1 -1
  162. package/dist/types/utils/node-tree/min-max-steps-to-leaf.d.ts +1 -1
  163. package/dist/types/utils/node-tree/min-max-steps-to-leaf.d.ts.map +1 -1
  164. package/dist/types/utils/node-tree/min-max-steps-to-origin.d.ts +1 -1
  165. package/dist/types/utils/node-tree/min-max-steps-to-origin.d.ts.map +1 -1
  166. package/dist/types/utils/node-tree/next-reachable-step-nodes.d.ts +1 -1
  167. package/dist/types/utils/node-tree/next-reachable-step-nodes.d.ts.map +1 -1
  168. package/dist/types/utils/nodes.d.ts +1 -1
  169. package/dist/types/utils/picked-config.d.ts +2 -1
  170. package/dist/types/utils/rules-logic.d.ts +6 -2
  171. package/dist/types/utils/storage.d.ts +1 -1
  172. package/dist/types/utils/storage.d.ts.map +1 -1
  173. package/package.json +22 -23
  174. package/dist/api-CoUkIxIr.cjs +0 -1
  175. package/dist/api-ahdSBQ3Y.js +0 -40
  176. package/dist/experience-instance-DurC3pE-.cjs +0 -1
  177. package/dist/plugin-CASdGtTX.cjs +0 -1
@@ -2,13 +2,16 @@
2
2
  layout: docs
3
3
  ---
4
4
 
5
- # Error handling
5
+ # Errors
6
6
 
7
- The Picked API returns errors using the standard GraphQL error format. This guide covers the error response shape, all error codes, and practical strategies for handling errors.
7
+ The Picked API returns an error in the standard GraphQL format. This guide covers the
8
+ shape of an error response, every error code, and what your code must do with each
9
+ one.
8
10
 
9
11
  ## Error response shape
10
12
 
11
- When an operation fails, the API returns an `errors` array in the response body. Each error object contains:
13
+ When an operation fails, the API returns an `errors` array in the response body. Each
14
+ error object holds these fields:
12
15
 
13
16
  ```json
14
17
  {
@@ -27,29 +30,31 @@ When an operation fails, the API returns an `errors` array in the response body.
27
30
 
28
31
  | Field | Description |
29
32
  |-------|-------------|
30
- | `message` | A human-readable error description. Suitable for logging but not for programmatic handling. |
31
- | `path` | The path to the field in the query that caused the error. |
32
- | `extensions.code` | A machine-readable error code. Use this for programmatic error handling. |
33
+ | `message` | A description of the error that a person can read. Put it in your log. Do not write code against it. |
34
+ | `path` | The path to the field in the query that made the error. |
35
+ | `extensions.code` | An error code that a machine can read. Write your code against this field. |
33
36
 
34
- Multiple errors may appear in a single response. The `data` field may be `null` if the entire operation failed, or it may contain partial data if only some fields failed.
37
+ One response can hold more than one error. The `data` field is `null` when the whole
38
+ operation failed. It holds part of the data when only some fields failed.
35
39
 
36
40
  ## Authentication error codes
37
41
 
38
- These errors relate to session creation, account management, OAuth, magic links, password operations, and MFA. They map to the `AuthErrorCode` enum in the schema.
42
+ These errors come from a session, an account, OAuth, a magic link, a password
43
+ operation, or MFA. They match the `AuthErrorCode` enum in the schema.
39
44
 
40
45
  | Code | Description |
41
46
  |------|-------------|
42
- | `INVALID_CREDENTIALS` | The email/password combination is incorrect. |
43
- | `EMAIL_NOT_CONFIRMED` | The account exists but the email address has not been verified. See [Authentication](/api/authentication#email-verification). |
44
- | `USER_NOT_FOUND` | No account exists with the provided email address. |
45
- | `USER_ALREADY_EXISTS` | An account with this email already exists. Returned during account creation. |
46
- | `WEAK_PASSWORD` | The provided password does not meet strength requirements. |
47
- | `INVALID_TOKEN` | The token (verification, reset, or magic link) is invalid or malformed. |
48
- | `TOKEN_EXPIRED` | The token has expired. The caller should request a new one. |
49
- | `MFA_CHALLENGE_FAILED` | The MFA verification code is incorrect. |
50
- | `MFA_FACTOR_NOT_FOUND` | The specified MFA factor does not exist or does not belong to the caller. |
51
- | `OAUTH_PROVIDER_ERROR` | An error occurred communicating with the OAuth provider (e.g., Google). |
52
- | `RATE_LIMITED` | Too many requests in a short period. The caller should wait and retry. |
47
+ | `INVALID_CREDENTIALS` | The email address and the password do not match. |
48
+ | `EMAIL_NOT_CONFIRMED` | The account is there, but nobody verified the email address. See [Authentication](/api/authentication#verify-an-email-address). |
49
+ | `USER_NOT_FOUND` | There is no account with that email address. |
50
+ | `USER_ALREADY_EXISTS` | An account with that email address is there already. The API returns this when you create an account. |
51
+ | `WEAK_PASSWORD` | The password is not strong enough. |
52
+ | `INVALID_TOKEN` | The token is invalid or malformed. This covers a verification token, a reset token, and a magic link token. |
53
+ | `TOKEN_EXPIRED` | The token expired. Ask for a new one. |
54
+ | `MFA_CHALLENGE_FAILED` | The MFA verification code is not correct. |
55
+ | `MFA_FACTOR_NOT_FOUND` | That MFA factor is not there, or it belongs to another caller. |
56
+ | `OAUTH_PROVIDER_ERROR` | The exchange with the OAuth provider, such as Google, failed. |
57
+ | `RATE_LIMITED` | Too many requests in a short period. Wait, then try again. |
53
58
 
54
59
  ### Example: invalid credentials
55
60
 
@@ -76,16 +81,18 @@ These errors relate to session creation, account management, OAuth, magic links,
76
81
 
77
82
  ## Authorization error codes
78
83
 
79
- Authorization errors occur when the caller lacks the required [scope](./authorization-and-scopes.md) for an operation.
84
+ An authorization error happens when the caller does not hold the
85
+ [scope](./authorization-and-scopes.md) that an operation needs.
80
86
 
81
87
  | Code | Description |
82
88
  |------|-------------|
83
- | `UNAUTHORIZED` | No valid authentication was provided. The request is missing the `Authorization` header or the `x-api-key` header, or the token/key is invalid. |
84
- | `FORBIDDEN` | The caller is authenticated but does not have the required scope for the operation. |
89
+ | `UNAUTHORIZED` | The request carries no valid authentication. It has no `Authorization` header and no `x-api-key` header, or the token is invalid. |
90
+ | `FORBIDDEN` | The caller is authenticated, but it does not hold the scope that the operation needs. |
85
91
 
86
- ### Example: insufficient scope
92
+ ### Example: the scope is not enough
87
93
 
88
- A caller with only `organization/read` attempting to delete an organization receives:
94
+ A caller that holds `organization/read` only tries to delete an organization. It
95
+ receives this:
89
96
 
90
97
  ```json
91
98
  {
@@ -106,52 +113,53 @@ A caller with only `organization/read` attempting to delete an organization rece
106
113
 
107
114
  ## Organization, member, and invitation error codes
108
115
 
109
- These errors relate to organization management, member operations, and invitation workflows. They map to the `ErrorCode` enum in the schema.
116
+ These errors come from an organization, a member operation, or an invitation. They
117
+ match the `ErrorCode` enum in the schema.
110
118
 
111
119
  ### Organization errors
112
120
 
113
121
  | Code | Description |
114
122
  |------|-------------|
115
- | `ORGANIZATION_NOT_FOUND` | The specified organization does not exist or the caller does not have access to it. |
116
- | `ORGANIZATION_ALREADY_EXISTS` | An organization with this name already exists. |
117
- | `SLUG_ALREADY_EXISTS` | The requested slug is already in use by another organization. |
118
- | `INVALID_SLUG` | The slug contains invalid characters. Slugs must be lowercase alphanumeric with hyphens. |
123
+ | `ORGANIZATION_NOT_FOUND` | That organization is not there, or the caller cannot reach it. |
124
+ | `ORGANIZATION_ALREADY_EXISTS` | An organization with that name is there already. |
125
+ | `SLUG_ALREADY_EXISTS` | Another organization uses that slug already. |
126
+ | `INVALID_SLUG` | The slug holds an invalid character. A slug takes lowercase letters, digits, and hyphens only. |
119
127
 
120
128
  ### Member errors
121
129
 
122
130
  | Code | Description |
123
131
  |------|-------------|
124
- | `MEMBER_NOT_FOUND` | The specified user is not a member of the organization. |
125
- | `MEMBER_ALREADY_EXISTS` | The user is already a member of the organization. |
126
- | `CANNOT_REMOVE_PRIMARY_OWNER` | The primary owner of an organization cannot be removed. |
127
- | `CANNOT_CHANGE_OWN_ROLE` | A member cannot change their own role. Another owner must perform this action. |
132
+ | `MEMBER_NOT_FOUND` | That user is not a member of the organization. |
133
+ | `MEMBER_ALREADY_EXISTS` | The user is a member of the organization already. |
134
+ | `CANNOT_REMOVE_PRIMARY_OWNER` | You cannot remove the primary owner of an organization. |
135
+ | `CANNOT_CHANGE_OWN_ROLE` | A member cannot change the role of that same member. Another owner must do it. |
128
136
 
129
137
  ### Invitation errors
130
138
 
131
139
  | Code | Description |
132
140
  |------|-------------|
133
- | `INVITATION_NOT_FOUND` | The specified invitation does not exist. |
134
- | `INVITATION_EXPIRED` | The invitation has expired and can no longer be accepted. |
135
- | `INVITATION_ALREADY_ACCEPTED` | The invitation has already been accepted. |
141
+ | `INVITATION_NOT_FOUND` | That invitation is not there. |
142
+ | `INVITATION_EXPIRED` | The invitation expired. Nobody can accept it now. |
143
+ | `INVITATION_ALREADY_ACCEPTED` | Somebody accepted the invitation already. |
136
144
 
137
145
  ### Project errors
138
146
 
139
147
  | Code | Description |
140
148
  |------|-------------|
141
- | `PROJECT_NOT_FOUND` | The specified project does not exist or the caller does not have access. |
149
+ | `PROJECT_NOT_FOUND` | That project is not there, or the caller cannot reach it. |
142
150
 
143
151
  ### General errors
144
152
 
145
153
  | Code | Description |
146
154
  |------|-------------|
147
- | `VALIDATION_ERROR` | The input failed validation. Check the `message` field for details about which field is invalid. |
148
- | `INTERNAL_ERROR` | An unexpected server error occurred. Retry the request or contact support if the issue persists. |
155
+ | `VALIDATION_ERROR` | The input failed a validation rule. Read the `message` field to learn which field is invalid. |
156
+ | `INTERNAL_ERROR` | The server met an unexpected error. Try the request again. Contact support when the error continues. |
149
157
 
150
- ## Handling errors in practice
158
+ ## What your code must do
151
159
 
152
- ### Check for errors first
160
+ ### Look for an error first
153
161
 
154
- Every response should be checked for the presence of an `errors` array before processing `data`:
162
+ Check every response for an `errors` array before you read `data`:
155
163
 
156
164
  ```javascript
157
165
  const response = await fetch('/graphql', {
@@ -171,41 +179,49 @@ if (result.errors) {
171
179
 
172
180
  switch (code) {
173
181
  case 'UNAUTHORIZED':
174
- // Redirect to login
182
+ // Send the user to the sign-in page.
175
183
  break;
176
184
  case 'FORBIDDEN':
177
- // Show a permissions error
185
+ // Show a permissions error.
178
186
  break;
179
187
  case 'RATE_LIMITED':
180
- // Wait and retry
188
+ // Wait, then try again.
181
189
  break;
182
190
  default:
183
- // Log or display the error message
191
+ // Put the message in the log, or show it.
184
192
  console.error(error.message);
185
193
  }
186
194
  }
187
195
  }
188
196
  ```
189
197
 
190
- ### Refresh expired tokens
198
+ ### Refresh a token that expired
191
199
 
192
- If a request returns `UNAUTHORIZED` and the caller has a refresh token, attempt a [session refresh](/api/authentication#session-refresh) before treating it as a login failure:
200
+ A request can return `UNAUTHORIZED` while the caller holds a refresh token. Try a
201
+ [session refresh](/api/authentication#refresh-a-session) first. Do not treat it as a
202
+ failure to sign in:
193
203
 
194
204
  ```javascript
195
205
  if (code === 'UNAUTHORIZED' && refreshToken) {
196
206
  const refreshResult = await sessionRefresh(refreshToken);
197
207
  if (refreshResult.session) {
198
- // Retry the original request with the new access token
208
+ // Try the first request again with the new access token.
199
209
  } else {
200
- // Redirect to login
210
+ // Send the user to the sign-in page.
201
211
  }
202
212
  }
203
213
  ```
204
214
 
205
- ### Handle partial data
215
+ ### Read data that is only part complete
206
216
 
207
- GraphQL can return partial data alongside errors. For example, a query that fetches an organization and its members might succeed for the organization but fail for the members if the caller lacks `organization_members/read`. In this case, the response contains both `data` (with the organization) and `errors` (for the members field). Always check both.
217
+ GraphQL can return part of the data together with an error. Take a query that reads
218
+ an organization and its members. It can succeed for the organization and fail for the
219
+ members, when the caller does not hold `organization_members/read`. The response then
220
+ holds `data` with the organization, and `errors` for the members field. Always read
221
+ both.
208
222
 
209
- ### Retry transient failures
223
+ ### Try again after a transient failure
210
224
 
211
- `INTERNAL_ERROR` and `RATE_LIMITED` are transient. For `RATE_LIMITED`, implement exponential backoff before retrying. For `INTERNAL_ERROR`, a single retry is usually sufficient.
225
+ `INTERNAL_ERROR` and `RATE_LIMITED` are both transient. For `RATE_LIMITED`, use an
226
+ exponential backoff before you try again. For `INTERNAL_ERROR`, one more try is
227
+ usually enough.
@@ -2,17 +2,21 @@
2
2
  layout: docs
3
3
  ---
4
4
 
5
- # Getting started
5
+ # Start here
6
6
 
7
- This guide walks you through your first interactions with the Picked GraphQL API, from sending a simple ping to making authenticated queries and mutations.
7
+ This guide takes you through your first calls to the Picked GraphQL API. It starts
8
+ with a ping and ends with an authenticated query and mutation.
8
9
 
9
10
  :::note
10
- This reference covers the authenticated GraphQL management API. To serve your published config and page content to your app, use the public, read-only [Delivery API](/delivery-api) instead.
11
+ This reference covers the GraphQL API that needs authentication. To serve your
12
+ published options and page content to your application, use the public
13
+ [Delivery API](/delivery-api), which is read-only.
11
14
  :::
12
15
 
13
16
  ## Playground
14
17
 
15
- Explore the API and run queries interactively in the [GraphQL Playground](https://api.picked.app/api/graphql).
18
+ Read the API and run a query in the
19
+ [GraphQL Playground](https://api.picked.app/api/graphql).
16
20
 
17
21
  ## API endpoint
18
22
 
@@ -22,7 +26,8 @@ All requests go to a single endpoint:
22
26
  POST https://api.picked.app/api/graphql
23
27
  ```
24
28
 
25
- Every request must use the `POST` method with a JSON body containing a `query` field and an optional `variables` field:
29
+ Every request must use the `POST` method. The JSON body must hold a `query` field,
30
+ and it can also hold a `variables` field:
26
31
 
27
32
  ```json
28
33
  {
@@ -41,7 +46,8 @@ curl -X POST https://api.picked.app/api/graphql \
41
46
 
42
47
  ## Ping the API
43
48
 
44
- Verify that the API is reachable with the `ping` query. This query does not require authentication.
49
+ Check that the API is reachable with the `ping` query. This query needs no
50
+ authentication.
45
51
 
46
52
  ```graphql
47
53
  query {
@@ -59,11 +65,12 @@ Response:
59
65
  }
60
66
  ```
61
67
 
62
- If you receive this response, the API is up and ready.
68
+ This response means that the API is ready.
63
69
 
64
70
  ## Authenticate
65
71
 
66
- Most operations require an access token. You obtain one by creating a session with your email and password.
72
+ Most operations need an access token. To get one, create a session with your email
73
+ address and your password.
67
74
 
68
75
  ```graphql
69
76
  mutation {
@@ -81,7 +88,8 @@ mutation {
81
88
  }
82
89
  ```
83
90
 
84
- A successful response returns a `Session` containing an `accessToken` and a `refreshToken`:
91
+ A successful response returns a `Session` with an `accessToken` and a
92
+ `refreshToken`:
85
93
 
86
94
  ```json
87
95
  {
@@ -98,9 +106,12 @@ A successful response returns a `Session` containing an `accessToken` and a `ref
98
106
  }
99
107
  ```
100
108
 
101
- If `requiresMfa` is `true`, you need to complete the MFA challenge before receiving a session. See the [Authentication](./authentication.md) guide for details.
109
+ When `requiresMfa` is `true`, you must complete the MFA challenge before you receive
110
+ a session. See the [Authentication](./authentication.md) guide.
102
111
 
103
- For server-to-server integrations, prefer [API key authentication](/api/authentication#api-key-authentication) over session tokens.
112
+ For a server-to-server integration, use
113
+ [API key authentication](/api/authentication#api-key-authentication) and not a
114
+ session token.
104
115
 
105
116
  ## Make an authenticated query
106
117
 
@@ -110,7 +121,8 @@ Pass the access token in the `Authorization` header as a Bearer token:
110
121
  Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
111
122
  ```
112
123
 
113
- Now you can query resources that require authentication. For example, fetch your user profile:
124
+ You can now query a resource that needs authentication. This example reads your user
125
+ profile:
114
126
 
115
127
  ```graphql
116
128
  query {
@@ -132,7 +144,8 @@ query {
132
144
 
133
145
  ## Make a mutation
134
146
 
135
- Mutations follow the same pattern: send a `POST` request with the `Authorization` header. For example, create an organization:
147
+ A mutation follows the same pattern. Send a `POST` request with the `Authorization`
148
+ header. This example creates an organization:
136
149
 
137
150
  ```graphql
138
151
  mutation {
@@ -165,11 +178,14 @@ Response:
165
178
  }
166
179
  ```
167
180
 
168
- Every mutation accepts an `input` argument and returns a payload object. The payload contains the created or updated resource on success, or errors in the top-level `errors` array on failure.
181
+ Every mutation takes an `input` argument and returns a payload object. On success the
182
+ payload holds the resource that the mutation created or updated. On failure the
183
+ `errors` array at the top level holds the errors.
169
184
 
170
- ## Error handling basics
185
+ ## Errors
171
186
 
172
- When something goes wrong, the API returns errors in the standard GraphQL `errors` array:
187
+ When something goes wrong, the API returns the errors in the standard GraphQL
188
+ `errors` array:
173
189
 
174
190
  ```json
175
191
  {
@@ -185,13 +201,16 @@ When something goes wrong, the API returns errors in the standard GraphQL `error
185
201
  }
186
202
  ```
187
203
 
188
- Check the `extensions.code` field for a machine-readable error code you can use to handle specific failures programmatically. See the [Error Handling](./error-handling.md) guide for the full list of error codes.
204
+ Read the `extensions.code` field. It holds an error code that your code can act on.
205
+ See the [Errors](./error-handling.md) guide for the full list of codes.
189
206
 
190
207
  ## Next steps
191
208
 
192
- Now that you can authenticate and make requests, explore these guides to go deeper:
209
+ You can now authenticate and make a request. These guides go into more detail:
193
210
 
194
- - [Authentication](./authentication.md) — email/password, OAuth, magic links, MFA, API keys, and session management
195
- - [Authorization and Scopes](./authorization-and-scopes.md) — understand what each role can access and how scopes control permissions
196
- - [Pagination](./pagination.md) — navigate large result sets with cursor-based pagination
197
- - [Error Handling](./error-handling.md) — handle every error code the API can return
211
+ - [Authentication](./authentication.md) — an email address and a password, OAuth,
212
+ magic links, MFA, API keys, and how to control a session.
213
+ - [Authorization and Scopes](./authorization-and-scopes.md) — what each role can
214
+ reach, and how a scope controls a permission.
215
+ - [Pagination](./pagination.md) — how to move through a large result with a cursor.
216
+ - [Errors](./error-handling.md) — every error code that the API can return.
@@ -4,11 +4,13 @@ layout: docs
4
4
 
5
5
  # Pagination
6
6
 
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.
7
+ The Picked API paginates every list field that can return a large result. It uses a
8
+ cursor, in the Relay-style pattern. This guide covers the connection pattern and
9
+ shows how to move through a result.
8
10
 
9
11
  ## Connection pattern
10
12
 
11
- Paginated fields return a **connection** object with the following shape:
13
+ A paginated field returns a **connection** object with this shape:
12
14
 
13
15
  ```graphql
14
16
  type ExampleConnection {
@@ -32,20 +34,21 @@ type PageInfo {
32
34
 
33
35
  | Field | Description |
34
36
  |-------|-------------|
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 |
37
+ | `edges` | An ordered list of edges. Each edge holds a `cursor` and a `node`, and the `node` holds the data. |
38
+ | `pageInfo.hasNextPage` | `true` when more results come after the last edge |
39
+ | `pageInfo.hasPreviousPage` | `true` when results come before the first edge |
40
+ | `pageInfo.startCursor` | The cursor of the first edge on the current page |
41
+ | `pageInfo.endCursor` | The cursor of the last edge on the current page |
42
+ | `totalCount` | The number of items on every page together |
41
43
 
42
44
  ## Forward pagination with `first` and `after`
43
45
 
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.
46
+ To move forward through the results, use two arguments. The `first` argument gives
47
+ the page size. The `after` argument gives the cursor to start after.
45
48
 
46
49
  ### First page
47
50
 
48
- Omit the `after` argument to fetch the first page:
51
+ Leave the `after` argument out to read the first page:
49
52
 
50
53
  ```graphql
51
54
  query {
@@ -89,16 +92,17 @@ query {
89
92
  }
90
93
  ```
91
94
 
92
- ## Checking for more pages
95
+ ## Check for more pages
93
96
 
94
- Before requesting the next page, check the `hasNextPage` field:
97
+ Read the `hasNextPage` field before you ask for the next page:
95
98
 
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
99
+ - `hasNextPage: true` — more results are available. Pass `endCursor` as the `after`
100
+ argument of the next request.
101
+ - `hasNextPage: false` — you read every result. Stop here.
98
102
 
99
103
  ## Full paginated query example
100
104
 
101
- The following example fetches all members of an organization, page by page:
105
+ This example reads every member of an organization, one page at a time:
102
106
 
103
107
  ```graphql
104
108
  # Page 1
@@ -154,7 +158,8 @@ Continue until `hasNextPage` returns `false`.
154
158
 
155
159
  ## Paginated fields
156
160
 
157
- The following fields in the schema return connection types and support `first`/`after` pagination:
161
+ These fields in the schema return a connection type. They all take the `first` and
162
+ `after` arguments:
158
163
 
159
164
  | Parent Type | Field | Connection Type |
160
165
  |------------|-------|----------------|
@@ -170,7 +175,12 @@ All of these fields accept the same `first` and `after` arguments and return the
170
175
 
171
176
  ## Tips
172
177
 
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.
178
+ - **The default page size** — the API applies a default limit when you leave `first`
179
+ out. Set `first` yourself to make sure that each page has the size you expect.
180
+ - **A cursor is opaque** — treat a cursor string as an opaque token. Do not parse it,
181
+ build it, or change it. Pass it back exactly as the API gave it.
182
+ - **The order is stable** — a connection returns its results in a stable order. The
183
+ same cursor always points at the same position in the result.
184
+ - **Use them with other fields** — you can use the pagination arguments together with
185
+ other query fields. One request that reads an organization and the first page of
186
+ its members is common, and it is efficient.
@@ -6,7 +6,8 @@ import { Screenshot } from '../../components/Screenshot'
6
6
 
7
7
  # API keys
8
8
 
9
- API keys let you access Picked's API programmatically. Use them for server-side integrations or CI/CD workflows.
9
+ An API key lets your code reach the Picked API. Use one for a server-side integration
10
+ or for a CI/CD workflow.
10
11
 
11
12
  <Screenshot
12
13
  route="/{orgSlug}/api-keys"
@@ -21,11 +22,12 @@ API keys let you access Picked's API programmatically. Use them for server-side
21
22
  4. Enter a description.
22
23
  5. Click **Create**.
23
24
 
24
- Copy the key immediately — it won't be shown again.
25
+ Copy the key immediately. The dashboard does not show it again.
25
26
 
26
- ## Using an API key
27
+ ## Use an API key
27
28
 
28
- Include your API key in the `Authorization` header when making requests to the [Picked API](/api).
29
+ Put your API key in the `Authorization` header of each request to the
30
+ [Picked API](/api).
29
31
 
30
32
  ```
31
33
  Authorization: Bearer your-api-key
@@ -33,8 +35,11 @@ Authorization: Bearer your-api-key
33
35
 
34
36
  ## Scopes
35
37
 
36
- API keys can be scoped to limit what they can access. When creating a key, select the scopes that match your integration's needs. A key can only perform actions allowed by its assigned scopes.
38
+ An API key carries scopes, and the scopes limit what the key can reach. Choose the
39
+ scopes that your integration needs when you create the key. A key can do only the
40
+ operations that its scopes permit.
37
41
 
38
42
  ## Revoke a key
39
43
 
40
- Revoke a key at any time from the API keys list. Click the revoke button next to the key you want to disable. Revoked keys stop working immediately.
44
+ You can revoke a key at any time from the API keys list. Click the revoke button next
45
+ to the key. A revoked key stops work immediately.
@@ -4,17 +4,21 @@ layout: docs
4
4
 
5
5
  # Chrome Extension
6
6
 
7
- The Picked Developer Tools extension adds a Picked panel to Chrome DevTools for inspecting and debugging your Picked integration on any page running the SDK.
7
+ The extension for the Picked Developer Tools adds a Picked panel to Chrome DevTools.
8
+ Use the panel to check and debug your Picked integration on any page that runs the
9
+ SDK.
8
10
 
9
11
  ![Picked Developer Tools](/chrome-extension-screenshot.jpg)
10
12
 
11
13
  ## Installation
12
14
 
13
- Install from the [Chrome Web Store](https://chromewebstore.google.com/detail/picked-developer-tools/nimmdamgnhlhdpngnalkpmnleebngidh).
15
+ Install the extension from the
16
+ [Chrome Web Store](https://chromewebstore.google.com/detail/picked-developer-tools/nimmdamgnhlhdpngnalkpmnleebngidh).
14
17
 
15
18
  ## Setup
16
19
 
17
- Add the `svelteDevtoolsPlugin` to your Picked client so the extension can connect to the SDK.
20
+ Add the `svelteDevtoolsPlugin` to your Picked client. The extension then connects to
21
+ the SDK.
18
22
 
19
23
  ```typescript
20
24
  import { createPicked } from '@picked/client'
@@ -30,7 +34,16 @@ const picked = createPicked({
30
34
 
31
35
  ## Custom Tools
32
36
 
33
- You can extend the Developer Tools with your own project-specific tools, surfaced under a **Custom Tools** tab. Each tool is a framework-adapted component — authored with the same `adaptReactComponent` / `adaptSvelteComponent` helpers you already use — so you can build it in your app's framework and it receives the live Picked client exactly like an experience component does (React: `usePicked()`; Svelte: `getPicked()`). Tools can both read client state and call client methods.
37
+ You can extend the Developer Tools with your own tools for one project. They appear
38
+ under a **Custom Tools** tab.
39
+
40
+ Each tool is a framework-adapted component. Write it with the same
41
+ `adaptReactComponent` or `adaptSvelteComponent` helper that you already use. You can
42
+ therefore build the tool in the framework of your application.
43
+
44
+ The tool receives the live Picked client, exactly as an experience component does. In
45
+ React, use `usePicked()`. In Svelte, use `getPicked()`. A tool can read client state
46
+ and call client methods.
34
47
 
35
48
  ```typescript
36
49
  import { createPicked } from '@picked/client'
@@ -48,4 +61,8 @@ const picked = createPicked({
48
61
  })
49
62
  ```
50
63
 
51
- The Developer Tools shell is rendered with Svelte, so a tool's framework must also be registered on the client. A React app needs `reactFrameworkPlugin` (for the tool) alongside the Svelte framework and `svelteDevtoolsPlugin` (for the shell). If a tool's framework isn't registered, its tab shows a warning instead of rendering.
64
+ Svelte renders the Developer Tools shell, so you must also register the framework of
65
+ your tool on the client. A React application needs `reactFrameworkPlugin` for the
66
+ tool, together with the Svelte framework and `svelteDevtoolsPlugin` for the shell.
67
+ When the framework of a tool is not registered, the tab of that tool shows a warning
68
+ and no content.