@aglyn/aglyn 1.0.0-beta.229 → 1.0.0-beta.231

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 (123) hide show
  1. package/package.json +11 -11
  2. package/src/lib/app-utils/analytics-events.d.ts +18 -0
  3. package/src/lib/app-utils/analytics-events.js +2 -0
  4. package/src/lib/app-utils/analytics-events.js.map +1 -1
  5. package/src/lib/app-utils/crm.d.ts +14 -1
  6. package/src/lib/app-utils/crm.js +19 -2
  7. package/src/lib/app-utils/crm.js.map +1 -1
  8. package/src/lib/app-utils/docs-help.generated.d.ts +111 -9
  9. package/src/lib/app-utils/docs-help.generated.js +272 -3
  10. package/src/lib/app-utils/docs-help.generated.js.map +1 -1
  11. package/src/lib/app-utils/docs-index.generated.js +810 -61
  12. package/src/lib/app-utils/docs-index.generated.js.map +1 -1
  13. package/src/lib/app-utils/host-status.d.ts +85 -0
  14. package/src/lib/app-utils/host-status.js +115 -0
  15. package/src/lib/app-utils/host-status.js.map +1 -0
  16. package/src/lib/app-utils/lockdown.js +1 -1
  17. package/src/lib/app-utils/lockdown.js.map +1 -1
  18. package/src/lib/app-utils/media-filter.d.ts +136 -0
  19. package/src/lib/app-utils/media-filter.js +400 -0
  20. package/src/lib/app-utils/media-filter.js.map +1 -0
  21. package/src/lib/app-utils/mobile-push.d.ts +98 -0
  22. package/src/lib/app-utils/mobile-push.js +97 -0
  23. package/src/lib/app-utils/mobile-push.js.map +1 -0
  24. package/src/lib/app-utils/notification-push.d.ts +38 -0
  25. package/src/lib/app-utils/notification-push.js +54 -0
  26. package/src/lib/app-utils/notification-push.js.map +1 -0
  27. package/src/lib/app-utils/notifications.d.ts +7 -0
  28. package/src/lib/app-utils/notifications.js.map +1 -1
  29. package/src/lib/app-utils/organizations.js +5 -2
  30. package/src/lib/app-utils/organizations.js.map +1 -1
  31. package/src/lib/app-utils/plan-entitlements.js +20 -0
  32. package/src/lib/app-utils/plan-entitlements.js.map +1 -1
  33. package/src/lib/app-utils/plugin-host-events.generated.d.ts +1 -1
  34. package/src/lib/app-utils/plugin-host-events.generated.js +164 -0
  35. package/src/lib/app-utils/plugin-host-events.generated.js.map +1 -1
  36. package/src/lib/app-utils/plugin-release-flags.generated.d.ts +1 -1
  37. package/src/lib/app-utils/plugin-release-flags.generated.js +7 -0
  38. package/src/lib/app-utils/plugin-release-flags.generated.js.map +1 -1
  39. package/src/lib/app-utils/realm-host-surface.generated.js +3 -0
  40. package/src/lib/app-utils/realm-host-surface.generated.js.map +1 -1
  41. package/src/lib/app-utils/release-flags.js +6 -2
  42. package/src/lib/app-utils/release-flags.js.map +1 -1
  43. package/src/lib/app-utils/scope-tokens.d.ts +16 -1
  44. package/src/lib/app-utils/scope-tokens.js +15 -1
  45. package/src/lib/app-utils/scope-tokens.js.map +1 -1
  46. package/src/lib/app-utils/site-journey.d.ts +143 -0
  47. package/src/lib/app-utils/site-journey.js +282 -0
  48. package/src/lib/app-utils/site-journey.js.map +1 -0
  49. package/src/lib/app-utils/site-list-query.d.ts +47 -0
  50. package/src/lib/app-utils/site-list-query.js +142 -0
  51. package/src/lib/app-utils/site-list-query.js.map +1 -0
  52. package/src/lib/app-utils/site-wide-outbox.d.ts +95 -0
  53. package/src/lib/app-utils/site-wide-outbox.js +117 -0
  54. package/src/lib/app-utils/site-wide-outbox.js.map +1 -0
  55. package/src/lib/app-utils/transfer-launcher-context.d.ts +6 -0
  56. package/src/lib/app-utils/transfer-launcher-context.js.map +1 -1
  57. package/src/lib/app-utils/upload-inspection.js +7 -0
  58. package/src/lib/app-utils/upload-inspection.js.map +1 -1
  59. package/src/lib/app-utils/webhook-delivery.js +4 -1
  60. package/src/lib/app-utils/webhook-delivery.js.map +1 -1
  61. package/src/lib/foundation/definitions/org-billing.types.d.ts +24 -0
  62. package/src/lib/foundation/definitions/org-billing.types.js.map +1 -1
  63. package/src/lib/foundation/definitions/organization.types.d.ts +18 -7
  64. package/src/lib/foundation/definitions/organization.types.js.map +1 -1
  65. package/src/lib/foundation/definitions/write-deny-coverage.util.d.ts +4 -1
  66. package/src/lib/foundation/definitions/write-deny-coverage.util.js +12 -2
  67. package/src/lib/foundation/definitions/write-deny-coverage.util.js.map +1 -1
  68. package/src/lib/plugin-manager/enabled-plugins.js +4 -2
  69. package/src/lib/plugin-manager/enabled-plugins.js.map +1 -1
  70. package/src/lib/plugin-manager/feature-plugins.d.ts +173 -0
  71. package/src/lib/plugin-manager/feature-plugins.js +62 -1
  72. package/src/lib/plugin-manager/feature-plugins.js.map +1 -1
  73. package/src/lib/plugin-manager/first-party-plugins.generated.js +251 -2
  74. package/src/lib/plugin-manager/first-party-plugins.generated.js.map +1 -1
  75. package/src/lib/plugin-manager/plugin-ai-capabilities.d.ts +192 -0
  76. package/src/lib/plugin-manager/plugin-ai-capabilities.js +157 -0
  77. package/src/lib/plugin-manager/plugin-ai-capabilities.js.map +1 -0
  78. package/src/lib/plugin-manager/plugin-checkout-extras.d.ts +168 -0
  79. package/src/lib/plugin-manager/plugin-checkout-extras.js +172 -0
  80. package/src/lib/plugin-manager/plugin-checkout-extras.js.map +1 -0
  81. package/src/lib/plugin-manager/plugin-contributions.d.ts +7 -0
  82. package/src/lib/plugin-manager/plugin-contributions.js +1 -1
  83. package/src/lib/plugin-manager/plugin-contributions.js.map +1 -1
  84. package/src/lib/plugin-manager/plugin-domain-events.d.ts +138 -0
  85. package/src/lib/plugin-manager/plugin-domain-events.js +148 -0
  86. package/src/lib/plugin-manager/plugin-domain-events.js.map +1 -0
  87. package/src/lib/plugin-manager/plugin-events.d.ts +51 -0
  88. package/src/lib/plugin-manager/plugin-events.js +4 -0
  89. package/src/lib/plugin-manager/plugin-events.js.map +1 -1
  90. package/src/lib/plugin-manager/plugin-fulfillment-providers.d.ts +101 -0
  91. package/src/lib/plugin-manager/plugin-fulfillment-providers.js +83 -0
  92. package/src/lib/plugin-manager/plugin-fulfillment-providers.js.map +1 -0
  93. package/src/lib/plugin-manager/plugin-permissions.js +21 -5
  94. package/src/lib/plugin-manager/plugin-permissions.js.map +1 -1
  95. package/src/lib/plugin-manager/plugin-person-records.d.ts +90 -0
  96. package/src/lib/plugin-manager/plugin-person-records.js +26 -0
  97. package/src/lib/plugin-manager/plugin-person-records.js.map +1 -1
  98. package/src/lib/plugin-manager/plugin-product-catalog.d.ts +204 -0
  99. package/src/lib/plugin-manager/plugin-product-catalog.js +43 -0
  100. package/src/lib/plugin-manager/plugin-product-catalog.js.map +1 -0
  101. package/src/lib/plugin-manager/plugin-shipment-records.d.ts +210 -0
  102. package/src/lib/plugin-manager/plugin-shipment-records.js +63 -0
  103. package/src/lib/plugin-manager/plugin-shipment-records.js.map +1 -0
  104. package/src/lib/plugin-manager/plugin-shipping-rates.d.ts +151 -0
  105. package/src/lib/plugin-manager/plugin-shipping-rates.js +62 -0
  106. package/src/lib/plugin-manager/plugin-shipping-rates.js.map +1 -0
  107. package/src/lib/plugin-manager/plugin-sms-messaging.d.ts +103 -0
  108. package/src/lib/plugin-manager/plugin-sms-messaging.js +39 -0
  109. package/src/lib/plugin-manager/plugin-sms-messaging.js.map +1 -0
  110. package/src/lib/plugin-manager/plugin-stock-levels.d.ts +81 -0
  111. package/src/lib/plugin-manager/plugin-stock-levels.js +32 -0
  112. package/src/lib/plugin-manager/plugin-stock-levels.js.map +1 -0
  113. package/src/lib/plugin-manager/plugin-tax-profile.d.ts +154 -0
  114. package/src/lib/plugin-manager/plugin-tax-profile.js +56 -0
  115. package/src/lib/plugin-manager/plugin-tax-profile.js.map +1 -1
  116. package/src/lib/plugin-manager/plugin-theme-font-catalog.d.ts +59 -0
  117. package/src/lib/plugin-manager/plugin-theme-font-catalog.js +40 -0
  118. package/src/lib/plugin-manager/plugin-theme-font-catalog.js.map +1 -0
  119. package/src/lib/plugin-manager/plugin-tracking-pages.d.ts +55 -0
  120. package/src/lib/plugin-manager/plugin-tracking-pages.js +76 -0
  121. package/src/lib/plugin-manager/plugin-tracking-pages.js.map +1 -0
  122. package/src/lib/plugin-manager/realm-host-aglyn.generated.js +3 -0
  123. package/src/lib/plugin-manager/realm-host-aglyn.generated.js.map +1 -1
@@ -37,7 +37,7 @@ export const DOCS_SECTION_INDEX = [
37
37
  title: 'A/B tests by AI: write variants, read the result',
38
38
  heading: 'Write variants',
39
39
  anchor: '#write-variants',
40
- text: 'The card sits in the experiment editor, beneath the list of variants it writes for.\n1. Give it the copy under test — the headline and copy as they stand on the page, or the subject line and message as they stand. For an email the control\'s subject and body are filled in from the first variant, so usually there is nothing to paste.\n2. Write variants. It writes between two and four: a test needs a first variant and at least one to compare against it, and the card stores no more than four. The first one it writes is your copy unchanged, so the test has something to measure against.\n3. Each variant comes back with a name, its copy, and one sentence saying what it changes and what that is testing.\nWhat a variant varies depends on what the test varies. An email variant varies its subject line, its preheader and its body; a page or a section variant varies the copy on it. A variant that fills the other kind\'s fields has them dropped.\nPutting them in {#putting-them-in}\nPut into the variants places the proposal in the editor\'s own fields, unsaved:\n- For an email, each variant takes its name, subject and body.\n- For a page or a section, each variant takes its name only. The copy itself is a page version, so you make one per variant in the editor and pin it above — read the proposed copy on the card and build from it.\nThen review them and Save the experiment, or Cancel.\nThe editor\'s list is the test\'s shape, and the card does not change it: a proposal is mapped onto the variants you already have, in order, and anything past them is ignored. Add a variant row first if you want a fourth.\nTwo things are refused rather than pasted. The fields are plain text, so a variant carrying markup is dropped; and a variant whose copy repeats another\'s is dropped, since two identical arms are not'
40
+ text: 'The card sits in the experiment editor, beneath the list of variants it writes for.\n1. Give it the copy under test — the headline and copy as they stand on the page, or the subject line and message as they stand. For an email the control\'s subject and body are filled in from the first variant, so usually there is nothing to paste.\n2. Write variants. It writes between two and four: a test needs a first variant and at least one to compare against it, and the card stores no more than four. The first one it writes is your copy unchanged, so the test has something to measure against.\n3. Each variant comes back with a name, its copy, and one sentence saying what it changes and what that is testing.\nWhat a variant varies depends on what the test varies. An email variant varies its subject line, its preheader and its body; a page or a section variant varies the copy on it. A variant that fills the other kind\'s fields has them dropped.\nPutting them in {#putting-them-in}\nPut into the variants places the proposal in the editor\'s own fields, unsaved:\n- For an email, each variant takes its name, subject and body.\n- For a page or a section, each variant takes its name. The copy itself lives in a version of the page, so the card also offers Make draft versions.\nDraft versions for a page or a section {#draft-versions}\nOnce the page under test — and, for a section test, the section — is picked in the editor, Make draft versions copies the page\'s published version once for every variant after the first, puts that variant\'s headline into the first heading and its body into the first plain text after it (inside the section for a section test, in the page\'s content for a page test), and saves each copy as a new unpublished version named A/B: and the variant\'s name. Each version is pinned to'
41
41
  },
42
42
  {
43
43
  path: '/ai/ab-tests-with-ai',
@@ -174,49 +174,63 @@ export const DOCS_SECTION_INDEX = [
174
174
  },
175
175
  {
176
176
  path: '/ai/automations-with-ai',
177
- title: 'Explain automations with AI',
177
+ title: 'Automations with AI',
178
178
  heading: '',
179
179
  anchor: '',
180
- text: 'Explain automations with AI\nOn Automation → Actions, Aglyn AI can explain an automation you already have, and tell you why one of its runs failed. Neither of them changes or runs an automation.'
180
+ text: 'Automations with AI\nOn the Automation page, Aglyn AI can draft an automation from a description, change or fix one you already have, explain what one does, and tell you why one of its runs failed. None of them runs an automation, switches one on, or changes one you have saved: what it drafts arrives as a new automation, switched off.'
181
181
  },
182
182
  {
183
183
  path: '/ai/automations-with-ai',
184
- title: 'Explain automations with AI',
185
- heading: 'Drafting an automation is not available yet',
184
+ title: 'Automations with AI',
185
+ heading: 'Draft an automation from a description',
186
186
  anchor: '#draft',
187
- text: 'Describing an automation and having Aglyn AI build it — "when someone submits the newsletter form, add them to the newsletter list, make them a lead and send them a welcome email" — is not open yet, on any plan.\nThe work is done up to a point a draft is not yet worth handing you: a description asking for several steps can come back as a draft holding one, because the answer is cut short at its size ceiling rather than re-asked. A one-step draft of a three-step description is worse than no draft, so the door stays shut until that is fixed.\nWhat follows on this page — Explain it and Why did this fail? — does not depend on it and is unaffected. When drafting opens, this section is replaced by how to use it.'
187
+ text: 'Choose Create with AI beside Add action and Recipes on Automation → Actions, or at the top of Automation → Workflows (in its empty state while it has none). Describe what should happen, and when — "when someone submits the newsletter form, add them to the newsletter list, make them a lead and send them a welcome email".\nThe automation is drafted switched off, using only the triggers and steps your plan includes. A list, campaign or other record your site does not have — or that the words could mean more than one of — is left as a placeholder for you to pick. When it is ready, Review it opens it in the Actions editor; from Workflows, that takes you to Actions, where it is listed.'
188
188
  },
189
189
  {
190
190
  path: '/ai/automations-with-ai',
191
- title: 'Explain automations with AI',
191
+ title: 'Automations with AI',
192
+ heading: 'Draft an org automation',
193
+ anchor: '#org-automations',
194
+ text: 'An org automation is written once for your workspace and runs on the sites you choose. On your workspace\'s Automation → Org automations, choose Create with AI in the card\'s header and describe what should happen, and when — "when someone books on any of our sites, make them a contact, tag them booked and send them a welcome email".\nThe automation is drafted from what an org automation can do: it starts only on something the server sees — a form, a lead, a booking, a member or a CRM event — and uses only the steps every site runs the same way, so nothing that belongs to one site\'s pages, workflows or webhooks. It opens placed on every site, so a campaign or dataset is filled in only when it is shared with every site. A list, campaign or dataset your workspace does not have, that is shared with only some sites, or that the words could mean more than one of, is left as a placeholder for you to pick once you have chosen the sites.\nNothing is saved for you. Open in the editor opens it in the org automation editor as a new automation, switched off. Choose the sites it runs on, check its steps, and save it with the editor\'s own Save — or close the editor, and nothing changes. When it is right, switch it on from the list.'
195
+ },
196
+ {
197
+ path: '/ai/automations-with-ai',
198
+ title: 'Automations with AI',
199
+ heading: 'Change or fix an automation',
200
+ anchor: '#change',
201
+ text: 'Open a saved action and use the box under Explain it:\n- Change with AI — describe the change: "also tag them newsletter, and wait a day before the email".\n- Fix with AI — asks Aglyn AI to fix whatever would stop the automation working as intended, such as a list your site no longer has, and to change nothing else.\nEither way you get a changed copy, switched off, beside the action you started from, which is left exactly as it is. The copy says what changed from the original — steps added, removed or changed, and whether its trigger or conditions changed — worked out by comparing the two, not taken from the AI\'s account of itself. Review the copy opens it in the editor. When it is right, switch the copy on and the original off.\nIt reads the action as it is saved, so save your edits first. An action that does something Aglyn AI does not write — starts on something a visitor does on a page, has a step that runs on the page, or only runs when an expression is true — cannot be changed this way, so that nothing you did not ask to lose goes missing; edit it in the editor instead. Workflows (lists of function calls) can be explained, not changed.'
202
+ },
203
+ {
204
+ path: '/ai/automations-with-ai',
205
+ title: 'Automations with AI',
192
206
  heading: 'Explain an automation',
193
207
  anchor: '#explain',
194
208
  text: 'Open a saved action or workflow and choose Explain it at the top of the editor. In a few minutes you get a plain-words account of what it does, step by step, and anything worth checking, such as a list your site no longer has or a placeholder nobody has filled in. It reads the automation as it is saved, so save your changes first.'
195
209
  },
196
210
  {
197
211
  path: '/ai/automations-with-ai',
198
- title: 'Explain automations with AI',
212
+ title: 'Automations with AI',
199
213
  heading: 'Find out why a run failed',
200
214
  anchor: '#why-a-run-failed',
201
215
  text: 'In an automation\'s Runs log, a failed run has Why did this fail?. It reads what the run history recorded about that run, together with the automation\'s settings, and answers with the most likely cause and how to fix it. Opening it again shows the same answer.'
202
216
  },
203
217
  {
204
218
  path: '/ai/automations-with-ai',
205
- title: 'Explain automations with AI',
219
+ title: 'Automations with AI',
206
220
  heading: 'What Aglyn AI is sent',
207
221
  anchor: '#what-is-sent',
208
- text: '- To explain an automation: how it is set up, including the text of its emails and messages and the names of the records it uses. Email addresses are removed first, a teammate is described only as a teammate, and on-page code is left out.\n- To explain a failed run: also when the run happened, what it did and the errors it recorded, with email addresses removed. What a visitor submitted, such as what they entered in a form, is never read.\nNo contact, lead, deal, form submission or list member is read for any of them.'
222
+ text: '- To draft an automation: your description, what your plan lets automations use, and the names of your site\'s forms (with their field names) and datasets. The names of your lists, campaigns, workflows, webhooks and pipeline stages are not sent; the words of the answer are matched to them on Aglyn\'s side.\n- To draft an org automation: your description, what your plan lets automations use, what an org automation can start on and do, and the names of your workspace\'s datasets. No site\'s forms are sent; the names of your lists, campaigns and pipeline stages are matched on Aglyn\'s side, as for a site\'s automation.\n- To change or fix one: the same, plus how the action is set up, as for an explanation below.\n- To explain an automation: how it is set up, including the text of its emails and messages and the names of the records it uses. Email addresses are removed first, a teammate is described only as a teammate, and on-page code is left out.\n- To explain a failed run: also when the run happened, what it did and the errors it recorded, with email addresses removed. What a visitor submitted, such as what they entered in a form, is never read.\nNo contact, lead, deal, form submission or list member is read for any of them.'
209
223
  },
210
224
  {
211
225
  path: '/ai/automations-with-ai',
212
- title: 'Explain automations with AI',
226
+ title: 'Automations with AI',
213
227
  heading: 'Who can use it',
214
228
  anchor: '#who-can-use-it',
215
- text: 'These jobs need the Generate with AI permission, on a site whose Automation plugin is on. See who can use Aglyn AI. A site that has switched AI off shows none of these controls. Each job spends AI credits; an automation\'s own runs count against your workspace\'s action runs, never your AI credits.'
229
+ text: 'These jobs need the Generate with AI permission, on a site whose Automation plugin is on. Drafting an org automation needs the same permission in the workspace, Automation switched on for it, and a plan with org automations; only members who can edit org automations see Create with AI there. See who can use Aglyn AI. A site that has switched AI off shows none of these controls. Each job spends AI credits; an automation\'s own runs count against your workspace\'s action runs, never your AI credits.'
216
230
  },
217
231
  {
218
232
  path: '/ai/automations-with-ai',
219
- title: 'Explain automations with AI',
233
+ title: 'Automations with AI',
220
234
  heading: 'Related',
221
235
  anchor: '#related',
222
236
  text: '- Actions builder\n- Aglyn AI\n- How Aglyn AI builds'
@@ -263,6 +277,62 @@ export const DOCS_SECTION_INDEX = [
263
277
  anchor: '#related',
264
278
  text: '- Generate a section\n- Aglyn AI\n- How Aglyn AI builds'
265
279
  },
280
+ {
281
+ path: '/ai/create-images',
282
+ title: 'Create images with AI',
283
+ heading: '',
284
+ anchor: '',
285
+ text: 'Create images with AI\nCreate with AI in the media library makes pictures from a description and adds them to the library you have open. There are two kinds:\n- Illustration or icon: a picture drawn as an SVG, sharp at any size. Choose an Illustration (a spot illustration or small scene), an Icon (one color, or two tones), a Pattern (a seamless background that tiles) or a Logo mark (a simple symbol without lettering). Available wherever Aglyn AI is.\n- Photo: a picture made by Google\'s image models. Offered only where photo creation is turned on for the deployment your workspace runs on; where it is not, the window shows only Illustration or icon.\nEach picture is stored the way a file you upload is stored: in the open folder, counted toward your storage, served from the same addresses, and with alt text you can edit.'
286
+ },
287
+ {
288
+ path: '/ai/create-images',
289
+ title: 'Create images with AI',
290
+ heading: 'Make a picture',
291
+ anchor: '#make-a-picture',
292
+ text: '1. Open Media, on a site or for the organization, and open the folder the pictures should land in.\n2. Choose Create with AI, beside Upload media. An empty library offers it beside its own Upload media button too.\n3. Where photos are on, choose Photo or Illustration or icon. For an illustration, choose its Kind.\n4. Describe the picture: what is in it, the setting, and the style you want.\n5. Choose a shape: Square 1:1, Landscape 4:3, Portrait 3:4, Wide 16:9 or Tall 9:16, and how many pictures to make, from one to four.\n6. For an illustration, choose its colors: Use my site\'s theme colors, which reads your site\'s theme, or Choose colors to pick up to six. The organization\'s library belongs to no single site, so there you choose the colors.\n7. The window shows what the pictures will cost in credits before you start. Choose Create.\nThe pictures appear in the library a few seconds later, selected, so you can move, tag or open them at once. Nothing is placed on a page: a picture is used only when you put it in an Image element, a gallery or anywhere else a media field asks for one.'
293
+ },
294
+ {
295
+ path: '/ai/create-images',
296
+ title: 'Create images with AI',
297
+ heading: 'What each picture gets',
298
+ anchor: '#what-each-picture-gets',
299
+ text: '- Alt text. A photo\'s is your description; an illustration\'s is a sentence the AI writes about what it drew. Edit it in the picture\'s details like any other alt text.\n- A file name made from the first few words of your description, starting ai- and numbered within the set: .svg for an illustration, the picture\'s own type for a photo.\n- A record of how it was made: the model, your description, the mode, the kind of illustration and the shape, kept with the file.\n- For a photo, an invisible watermark. Google marks every picture its image models make with its SynthID watermark, so the picture can later be identified as generated. You cannot see it, and it does not change how the picture looks.'
300
+ },
301
+ {
302
+ path: '/ai/create-images',
303
+ title: 'Create images with AI',
304
+ heading: 'Credits',
305
+ anchor: '#credits',
306
+ text: 'Pictures are metered in AI credits from the workspace\'s pool. The window shows an estimate before you create anything:\n| Mode | About, per picture | What it is made of |\n| Illustration or icon | 18 credits | The words the AI reads and writes to draw the SVG, at the same rates as other AI text |\n| Photo | 108 credits | The picture, plus the description and the thinking the image model does before it draws |\nWhat is charged is what was actually spent, so a picture can cost a little more or less than its estimate, and an illustration that needed a second attempt costs about twice its estimate. You are charged only for pictures that reach your library:\n- a picture the safety filter holds back is not charged;\n- an illustration that does not come out right is not charged. The window says This one\'s on us — you weren\'t charged.\n- a picture your library could not store, because your storage is full for example, is not charged;\n- when the AI service fails, nothing is charged.\nA Free workspace spends from its monthly allowance and is told before it starts when the pictures it asked for would cost more than it has left. A paid workspace past its included band keeps working at its plan\'s overage rate unless the workspace stops AI at the band, the same as every other AI request.'
307
+ },
308
+ {
309
+ path: '/ai/create-images',
310
+ title: 'Create images with AI',
311
+ heading: 'Safe by construction',
312
+ anchor: '#safety',
313
+ text: 'An illustration is checked before it is stored. It has to be one SVG in the shape you chose, no larger than 200 KB, and self-contained: no scripts, no links, no embedded images or web pages, and nothing loaded from anywhere else, such as a font. An illustration that fails the check is drawn again once with the problem pointed out; if the second one fails too, it is not stored and not charged. The media library then removes anything unsafe from every SVG it stores, as it does for an SVG you upload.\nThe AI declines to draw a real company\'s or organization\'s logo, a trademark or a recognizable brand symbol, a real, named person, and anything sexual, hateful, violent or otherwise unsafe; the window says why, and a declined request on a Free workspace costs nothing. A Logo mark is always a symbol without lettering.\nPhotos are checked by Google\'s safety filters, set to block content they rate as a medium risk or higher, and Google\'s own policies refuse some content whatever is asked, such as photorealistic depictions of children or celebrities that its policies do not allow. A description that is declined is answered with a message and no picture is charged.'
314
+ },
315
+ {
316
+ path: '/ai/create-images',
317
+ title: 'Create images with AI',
318
+ heading: 'What is sent',
319
+ anchor: '#what-is-sent',
320
+ text: '- Illustration or icon: your description, the kind and shape of picture, and your site\'s theme colors or the colors you chose are sent to the AI service every other Aglyn AI feature uses.\n- Photo: your description and the shape you chose are sent to Google\'s image models on Vertex AI.\nNothing else is sent: no other content of your site, no file from your library, and no name, email address or account identifier. The pictures come back to Aglyn and are stored in your library; your description is kept with each picture as part of its record of how it was made.'
321
+ },
322
+ {
323
+ path: '/ai/create-images',
324
+ title: 'Create images with AI',
325
+ heading: 'Who can use it',
326
+ anchor: '#who-can-use-it',
327
+ text: 'Creating images needs the Generate with AI permission and a plan that includes AI generation — see who can use Aglyn AI. It also needs permission to upload to the library you have open, and on a site whose AI is switched off it is not offered.'
328
+ },
329
+ {
330
+ path: '/ai/create-images',
331
+ title: 'Create images with AI',
332
+ heading: 'Related',
333
+ anchor: '#related',
334
+ text: '- Media Library & CDN\n- Aglyn AI overview\n- AI allotments, usage and model choice'
335
+ },
266
336
  {
267
337
  path: '/ai/crm-by-ai',
268
338
  title: 'The AI CRM built into Aglyn',
@@ -429,7 +499,7 @@ export const DOCS_SECTION_INDEX = [
429
499
  title: 'Generate a section on the canvas',
430
500
  heading: 'What it builds',
431
501
  anchor: '#what-it-builds',
432
- text: 'The section is built from your site\'s real components and follows the building rules, so it drops into your design rather than sitting on top of it:\n- Your theme\'s colors, spacing and text styles, never a fixed color value.\n- A grid that breaks down, showing one column on a phone and stepping up on larger screens, at your theme\'s own breakpoints.\n- Headings in order, so the page still reads well to screen readers and search engines.\n- Images from your media library, each with alt text, or an empty slot for you to fill. Never an image linked from another site.\n- A repeat built once. A block that appears three or more times becomes one reusable component placed as instances — or, on a plan without reusable components, is built into the page each time.'
502
+ text: 'The section is built from your site\'s real components and follows the building rules, so it drops into your design rather than sitting on top of it:\n- Your theme\'s colors, spacing and text styles, never a fixed color value.\n- A grid that breaks down, showing one column on a phone and stepping up on larger screens, at your theme\'s own breakpoints.\n- Headings in order, so the page still reads well to screen readers and search engines.\n- Images from your media library, each with alt text, or an empty slot for you to fill. Never an image linked from another site.\n- A repeat built once. A block that appears three or more times becomes one reusable component placed as instances — or, on Free, whose one component per site is yours to spend, is built into the page each time.'
433
503
  },
434
504
  {
435
505
  path: '/ai/generate-section',
@@ -485,7 +555,7 @@ export const DOCS_SECTION_INDEX = [
485
555
  title: 'How Aglyn AI builds',
486
556
  heading: 'The building rules',
487
557
  anchor: '#the-building-rules',
488
- text: '1. Repeats become one reusable component. A block that appears three or more times on a page, such as the same card with different words, is built once as a reusable component and placed as instances. The AI looks for a component you already have first, and never makes a second copy of one. On a plan without reusable components, such as Free, the block is built into the page each time it repeats instead. Either way, a list of such blocks is one section of the page, never a section for each block.\n2. Site-wide regions live in the layout. Headers, navigation, footers, announcement bars and cookie notices belong to the site\'s layout. A generated page sits in your layout and never carries its own copy of them.\n3. Forms are built on the Forms page, then placed. A form is created with its fields, validation, consent and routing on the Forms page, and a page places it by reference, so you edit it in one place. A generated page never draws form fields of its own: when your site has no saved form to place and no room for another, the page goes without one. A search is never built as a form, because a form collects submissions: the AI places a Search Box for your site search, or a Collection Search for the entries of one collection.\n4. Similar pages share one template. Pages that share a structure and differ by content, such as products, locations, team members or services, are built from one template or bound to a collection.\n5. Colors, spacing and type come from your theme. Generated content uses your theme\'s colors, spacing scale and text styles, never a fixed color value. A color your theme lacks is proposed as a theme change for you to review. A link or button on a colored band, such as a footer in your primary color, uses the band\'s text color, so it stays readable.\n6. Emai'
558
+ text: '1. Repeats become one reusable component. A block that appears three or more times on a page, such as the same card with different words, is built once as a reusable component and placed as instances. The AI looks for a component you already have first, and never makes a second copy of one. On Free, which includes one reusable component per site and leaves it for you to spend, the block is built into the page each time it repeats instead. Either way, a list of such blocks is one section of the page, never a section for each block.\n2. Site-wide regions live in the layout. Headers, navigation, footers, announcement bars and cookie notices belong to the site\'s layout. A generated page sits in your layout and never carries its own copy of them.\n3. Forms are built on the Forms page, then placed. A form is created with its fields, validation, consent and routing on the Forms page, and a page places it by reference, so you edit it in one place. A generated page never draws form fields of its own: when your site has no saved form to place and no room for another, the page goes without one. A search is never built as a form, because a form collects submissions: the AI places a Search Box for your site search, or a Collection Search for the entries of one collection.\n4. Similar pages share one template. Pages that share a structure and differ by content, such as products, locations, team members or services, are built from one template or bound to a collection.\n5. Colors, spacing and type come from your theme. Generated content uses your theme\'s colors, spacing scale and text styles, never a fixed color value. A color your theme lacks is proposed as a theme change for you to review. A link or button on a colored band, such as a footer in your primary color, uses the band\'s text c'
489
559
  },
490
560
  {
491
561
  path: '/ai/how-aglyn-ai-builds',
@@ -508,6 +578,118 @@ export const DOCS_SECTION_INDEX = [
508
578
  anchor: '#related',
509
579
  text: '- AI Assist\n- AI Generate Section\n- Generate a layout\n- Generate a page template\n- Generate a reusable component\n- Generate a page from a brief\n- Generate an email with AI'
510
580
  },
581
+ {
582
+ path: '/ai/logic-with-ai',
583
+ title: 'Functions and variables with AI',
584
+ heading: '',
585
+ anchor: '',
586
+ text: 'Functions and variables with AI\nOn Logic — the Functions & Variables page — Aglyn AI can write a function or a variable from a description, change or fix a function you already have, and explain what one works out. On the same page, a broken reference an automation holds offers Fix with AI.\nNothing is saved for you. What Aglyn AI writes opens in the function or variable editor, unsaved, exactly as if you had typed it. Test it, change anything, and save it with the editor\'s own Save — or close the editor and nothing changes.'
587
+ },
588
+ {
589
+ path: '/ai/logic-with-ai',
590
+ title: 'Functions and variables with AI',
591
+ heading: 'Write a function from a description',
592
+ anchor: '#function',
593
+ text: 'Choose Create with AI at the top of the Functions card and describe what it should work out — "a shipping quote: free over our free-shipping amount, otherwise the flat rate plus 2 per kilo".\nThe function is written only from what the editor\'s evaluator runs: + - /, parentheses, the built-ins the editor lists, the function\'s own parameters and locals, and your site\'s variables by name (a dictionary\'s members as name.member). Before you see it, it is checked — every expression must parse, every name it reads must be its own or one of your site\'s variables, it may set only its own parameters and locals, and it is run once with each parameter at a starting value. One that fails is sent back to be rewritten, saying why. Where your description needs a number your site does not hold, it becomes a parameter rather than a guess.\nWhen it is ready, Open in the editor opens it as a new function, unsaved. A plan\'s function limit applies as it does to Add function.'
594
+ },
595
+ {
596
+ path: '/ai/logic-with-ai',
597
+ title: 'Functions and variables with AI',
598
+ heading: 'Write a variable',
599
+ anchor: '#variable',
600
+ text: 'Create with AI at the top of the Variables card writes one site variable — a name, a type and a value in that type\'s stored form, such as a dictionary of plan prices {"starter":19,"pro":49}. It opens in the variable editor, unsaved.'
601
+ },
602
+ {
603
+ path: '/ai/logic-with-ai',
604
+ title: 'Functions and variables with AI',
605
+ heading: 'Change, fix or explain a function',
606
+ anchor: '#change',
607
+ text: 'Open a saved function. The box at the top of its editor offers:\n- Explain it — what the function works out from what it is given, operation by operation, and anything worth checking, such as a condition that can never hold.\n- Change with AI — describe the change: "add a 10% discount when the order is over 200".\n- Fix with AI — fixes whatever would stop the function working, such as a name your site does not have, and changes nothing else.\nA change is checked exactly as a new function is. Put it in the editor replaces what the editor holds with the changed function, unsaved; Cancel leaves the saved function as it was. Each reads the function as it is saved, so save your edits first.'
608
+ },
609
+ {
610
+ path: '/ai/logic-with-ai',
611
+ title: 'Functions and variables with AI',
612
+ heading: 'Fix a broken reference',
613
+ anchor: '#broken-references',
614
+ text: 'The Reference health card lists references that point at something your site no longer has. On a reference an automation holds — a list, a campaign, a workflow, a dataset or a webhook it names — Fix with AI drafts a changed copy of that automation, switched off, beside the original, which is left as it is: see Change or fix an automation. Review it on the Automation page and switch it on in place of the old one. A workflow\'s, a variable\'s and a page\'s references are fixed by hand.'
615
+ },
616
+ {
617
+ path: '/ai/logic-with-ai',
618
+ title: 'Functions and variables with AI',
619
+ heading: 'What Aglyn AI is sent',
620
+ anchor: '#what-is-sent',
621
+ text: 'Your description; your site\'s variables, by name, type and value; the names of your site\'s functions; and, to change, fix or explain a function, that function\'s definition. Nothing a visitor entered is read.'
622
+ },
623
+ {
624
+ path: '/ai/logic-with-ai',
625
+ title: 'Functions and variables with AI',
626
+ heading: 'Who can use it',
627
+ anchor: '#who-can-use-it',
628
+ text: 'These jobs need the Generate with AI permission, on a site whose Logic plugin is on. See who can use Aglyn AI. A site that has switched AI off shows none of these controls. Each job spends AI credits.'
629
+ },
630
+ {
631
+ path: '/ai/logic-with-ai',
632
+ title: 'Functions and variables with AI',
633
+ heading: 'Related',
634
+ anchor: '#related',
635
+ text: '- Bindings, variables & functions\n- Automations with AI\n- Aglyn AI'
636
+ },
637
+ {
638
+ path: '/ai/marketing-with-ai',
639
+ title: 'Marketing with AI: overlays, campaigns and your numbers',
640
+ heading: '',
641
+ anchor: '',
642
+ text: 'Marketing with AI\nYour site\'s Marketing page has its own AI doors. Each one sits beside the thing it works on, and each one stops short of anything a visitor or a recipient would see: an overlay it creates is switched off, a campaign it drafts is aimed at nobody, and copy it writes waits in the editor until you save it.'
643
+ },
644
+ {
645
+ path: '/ai/marketing-with-ai',
646
+ title: 'Marketing with AI: overlays, campaigns and your numbers',
647
+ heading: 'Write overlay copy',
648
+ anchor: '#write-overlay-copy',
649
+ text: 'Open an announcement bar or a popup from Marketing → Overlays and the editor carries a Write with AI box among its fields.\n1. Say what the overlay is for — the offer, the news, who it is for. When the overlay already has copy, that copy is sent too, so it can be improved rather than replaced; you can leave the box empty to ask for exactly that.\n2. Write with AI. It writes a bar\'s one line, or a popup\'s headline, body and button label, inside the lengths the editor allows.\n3. For a popup it also suggests when it opens — after a delay, on scroll or on exit intent, the triggers the editor itself offers, with a value inside that trigger\'s range — or leaves the trigger as it is.\n4. Put in the fields fills the editor\'s own fields. Nothing is saved until you press Save; Cancel leaves the overlay as it was.\nIt never writes the button\'s link, the pages the overlay shows on, its schedule, or whether it is switched on. Those are yours, in the same editor.'
650
+ },
651
+ {
652
+ path: '/ai/marketing-with-ai',
653
+ title: 'Marketing with AI: overlays, campaigns and your numbers',
654
+ heading: 'Create an overlay',
655
+ anchor: '#create-an-overlay',
656
+ text: 'Beside New bar and New popup, and on the list while it is empty, Create with AI turns a brief into a new overlay.\n1. Choose Popup or Announcement bar, and say what it is for.\n2. Create the overlay. The copy is written as above, and the overlay is saved switched off and opened in the editor.\n3. Add its link, its pages and its schedule, then turn it on from the list when you are ready. Until then no visitor sees it.\nA fact the brief did not give — a discount, a date, a price — arrives in square brackets for you to fill rather than invented.'
657
+ },
658
+ {
659
+ path: '/ai/marketing-with-ai',
660
+ title: 'Marketing with AI: overlays, campaigns and your numbers',
661
+ heading: 'Create a campaign',
662
+ anchor: '#create-a-campaign',
663
+ text: 'On Marketing → Campaigns, beside Create campaign and on the list while it is empty, Create with AI turns a brief into a campaign.\n1. On your organization\'s Marketing page, pick the site the campaign is placed on and sent as. On a site\'s own page it is that site.\n2. Give it a name if you like, and say what the campaign is for.\n3. Write the campaign. The job writes an email design — with three subject lines and three preheaders — and a draft campaign holding that email. Follow it in the dialog or in AI jobs, then open the draft campaign.\n4. Pick who receives it, check the email and schedule it. Until you do, nothing is sent, scheduled or queued, and the campaign is aimed at nobody.\nWhen your brief names one of your lists, the campaign\'s note says which one, and when that list\'s past campaigns were opened most — see who receives it.\nA plan that sends no campaign email gets Write a campaign email with AI instead: the same dialog writes the email design on its own, which you can use once your plan sends campaigns. Upgrading is done in Billing.'
664
+ },
665
+ {
666
+ path: '/ai/marketing-with-ai',
667
+ title: 'Marketing with AI: overlays, campaigns and your numbers',
668
+ heading: 'Ask about these numbers',
669
+ anchor: '#ask-about-these-numbers',
670
+ text: 'The Conversions section and each campaign\'s report carry Ask AI about these numbers in their header. It opens Insights on the site the figures are — on your organization\'s Conversions section, the site you picked; on a campaign\'s report, the site the email was sent as — with a question about what the page shows already in the box. Change it if you like, pick a window, and ask.\nThe answer reads your site\'s figures, the same ones these pages show:\n- Campaign conversions — form submissions, leads, contacts and bookings credited to a campaign in the window, one row each, by the touch that earned the credit: a campaign email, a page filed under a campaign, a labeled link or a sequence email. The rows are never added together, because one visit can make a submission, a lead and a contact. A conversion credited to nothing has no record and is not counted.\n- Campaign revenue — for each campaign email sent in the window, the orders credited to it and the gross, refunded and net amounts, one row per currency; different currencies are never added together.\n- Beside those, your campaign emails\' delivery and engagement, your A/B tests, your forms, your traffic and your store\'s sales, where your plan includes them.\nEvery insight cites the rows its numbers come from. Nothing is changed or sent. The same question can be asked from the Assist panel anywhere on a site\'s Marketing page.'
671
+ },
672
+ {
673
+ path: '/ai/marketing-with-ai',
674
+ title: 'Marketing with AI: overlays, campaigns and your numbers',
675
+ heading: 'What is sent',
676
+ anchor: '#what-is-sent',
677
+ text: 'For overlay copy: your brief, whether it is a bar or a popup, the triggers the editor offers, and the overlay\'s current copy when there is some. Nothing about your visitors, your figures or your other overlays is sent.\nFor a campaign: your brief, the name you gave it and what your site already has — the same as generating an email. Your lists, contacts and past send figures are read on the server and are not sent.\nFor a question about your numbers: the question, the window and the tables of totals the answer reads — never a visitor, contact, order or submission. See Insights → Privacy.'
678
+ },
679
+ {
680
+ path: '/ai/marketing-with-ai',
681
+ title: 'Marketing with AI: overlays, campaigns and your numbers',
682
+ heading: 'Who can use it',
683
+ anchor: '#who-can-use-it',
684
+ text: 'The doors appear for a member who may generate with AI, on a workspace whose plan includes AI generation and on a site with AI switched on. The overlay doors also need marketing overlays in the plan. A campaign also needs the Email plugin on for the site. Each request is metered in AI credits like any other — see credits and caps.'
685
+ },
686
+ {
687
+ path: '/ai/marketing-with-ai',
688
+ title: 'Marketing with AI: overlays, campaigns and your numbers',
689
+ heading: 'Related',
690
+ anchor: '#related',
691
+ text: '- Marketing overlays — the bars and popups themselves.\n- Aglyn AI — every AI door, and the rule that it only ever writes drafts.'
692
+ },
511
693
  {
512
694
  path: '/ai/overview',
513
695
  title: 'Aglyn AI: the AI website builder',
@@ -527,7 +709,7 @@ export const DOCS_SECTION_INDEX = [
527
709
  title: 'Aglyn AI: the AI website builder',
528
710
  heading: 'What it can build',
529
711
  anchor: '#what-it-can-build',
530
- text: 'Each capability has its own page, next to the thing it builds:\n| You want | Where you start | The page |\n| A page from a brief | Pages → Create with AI | Generate a page |\n| A whole small site | Pages, or Sites for several at once | Generate a site |\n| Many client sites, run as an agency | Sites | An AI website builder for agencies |\n| A layout — header, navigation, footer | Layouts → Create with AI | Generate a layout |\n| A page template | Templates → Create with AI | Generate a page template |\n| A reusable component | Components → Create with AI | Generate a component |\n| A form | Forms → Create with AI | Generate a form |\n| A section on the canvas | The Besigner | Generate a section |\n| Copy, rewritten or fresh | Any text in the Besigner | Rewrite and write copy |\n| A change to your theme | Setup → Theme | Change your theme with AI |\n| Search titles and descriptions | SEO | SEO by AI |\n| Product copy, catalog and discount ideas | Commerce | Products with AI |\n| Help working the CRM | A record, the composer, an import | CRM by AI |\n| A designed email | Email → Create with AI | Generate an email |\n| A campaign | Campaigns | Generate an email |\n| Variants for an A/B test, and its result in words | Marketing → Experiments | A/B tests by AI |\n| What your analytics mean | Analytics → Insights | Insights |\n| A change to the page you have open | The Assist panel, in the Besigner | Edits in the Besigner |\nEverything in that table follows the same building rules — reuse before creating, your theme\'s colors and spacing, one reusable component for a repeat, images from your media library with alt text, and a measured size. They are written out on How Aglyn AI builds, and every plan and every generated document is checked against them before you see it.\nNot available yet {#not-ye'
712
+ text: 'Each capability has its own page, next to the thing it builds:\n| You want | Where you start | The page |\n| A page from a brief | Pages → Create with AI | Generate a page |\n| A whole small site | Pages, or Sites for several at once | Generate a site |\n| Many client sites, run as an agency | Sites | An AI website builder for agencies |\n| A layout — header, navigation, footer | Layouts → Create with AI | Generate a layout |\n| A page template | Templates → Create with AI | Generate a page template |\n| A reusable component | Components → Create with AI | Generate a component |\n| A form | Forms → Create with AI | Generate a form |\n| Illustrations, icons, patterns, logo marks and photos | Media → Create with AI | Create images with AI |\n| A section on the canvas | The Besigner | Generate a section |\n| Copy, rewritten or fresh | Any text in the Besigner | Rewrite and write copy |\n| A change to your theme | Setup → Theme | Change your theme with AI |\n| Search titles and descriptions | SEO | SEO by AI |\n| Product copy, catalog and discount ideas | Products → Create with AI, and Build your catalog with AI on the products page | Products with AI |\n| Help working the CRM | A record, the composer, an import | CRM by AI |\n| A designed email | Emails → Templates → Create with AI | Generate an email |\n| A campaign | Marketing → Campaigns → Create with AI, or Also draft a campaign on an email | Generate an email |\n| Variants for an A/B test, and its result in words | Marketing → Experiments | A/B tests by AI |\n| Announcement bar and popup copy, or a new overlay | Marketing → Overlays | Marketing with AI |\n| What your analytics mean | Analytics → Insights | Insights |\n| What your campaigns caused and earned | Marketing → Conversions, or a campaign\'s report | Marketing with AI |\n| An autom'
531
713
  },
532
714
  {
533
715
  path: '/ai/overview',
@@ -555,14 +737,14 @@ export const DOCS_SECTION_INDEX = [
555
737
  title: 'Aglyn AI: the AI website builder',
556
738
  heading: 'Switch AI off for one site',
557
739
  anchor: '#switch-ai-off-for-one-site',
558
- text: 'AI is on for every site in a workspace. A site admin can switch it off for one site on that site\'s Admin → Plugins → AI page, and the page says, beside the switch, what switching it off stops and what it leaves running.\nWith AI off for a site:\n- the assistant, Create with AI on the Pages, Templates, Layouts, Forms and Components pages, the SEO and theme cards, the editor\'s Rewrite with AI, Generate a section with AI and Make a reusable component with AI controls, and the AI columns on the site\'s collaborators card are gone from that site;\n- every AI request made for the site is refused with AI is switched off for this site., including one sent from a tab that was open before the switch;\n- an AI job already queued for the site stops with the same sentence, and spends no credits. A job that stopped does not restart when AI is switched back on.\nSwitching AI off for a site does not stop the workspace\'s AI add-on, credits, allotments or overage billing. AI keeps working on the workspace\'s other sites and on workspace pages such as Billing, and an agency batch still builds the sites in it that have AI on.'
740
+ text: 'AI is on for every site in a workspace. A site admin can switch it off for one site on that site\'s Admin → Plugins → AI page, and the page says, beside the switch, what switching it off stops and what it leaves running.\nWith AI off for a site:\n- the assistant, Create with AI on the Pages, Templates, Layouts, Forms, Components and Media pages, the SEO and theme cards, the editor\'s Rewrite with AI, Generate a section with AI and Make a reusable component with AI controls, and the AI columns on the site\'s collaborators card are gone from that site;\n- every AI request made for the site is refused with AI is switched off for this site., including one sent from a tab that was open before the switch;\n- an AI job already queued for the site stops with the same sentence, and spends no credits. A job that stopped does not restart when AI is switched back on.\nSwitching AI off for a site does not stop the workspace\'s AI add-on, credits, allotments or overage billing. AI keeps working on the workspace\'s other sites and on workspace pages such as Billing, and an agency batch still builds the sites in it that have AI on.'
559
741
  },
560
742
  {
561
743
  path: '/ai/overview',
562
744
  title: 'Aglyn AI: the AI website builder',
563
745
  heading: 'What happens to what you send',
564
746
  anchor: '#what-is-sent',
565
- text: 'A build job is sent your brief and what it needs to build against it — the names of the components, layouts, forms and datasets your site already has, your theme\'s values, and the copy of anything it is starting from. Each capability\'s page says exactly what its own job is sent: the CRM page lists what a record sends, and the automation page what is removed first.\nYour brief is customer text and is kept with the job for 180 days, then deleted. No contact, lead, deal, form submission or list member is read to build a page.'
747
+ text: 'A build job is sent your brief and what it needs to build against it — the names of the components, layouts, forms and datasets your site already has, your theme\'s values, and the copy of anything it is starting from. Each capability\'s page says exactly what its own job is sent: the CRM page lists what a record sends, and the automation page what is removed first.\nA photo made with Create images with AI is the one thing served by Google rather than by the assistant\'s own model: it sends the description you type and the shape you choose, and nothing else of your site.\nYour brief is customer text and is kept with the job for 180 days, then deleted. No contact, lead, deal, form submission or list member is read to build a page.'
566
748
  },
567
749
  {
568
750
  path: '/ai/overview',
@@ -597,7 +779,7 @@ export const DOCS_SECTION_INDEX = [
597
779
  title: 'Product copy and catalogs with AI',
598
780
  heading: 'Propose a first catalog',
599
781
  anchor: '#propose-a-first-catalog',
600
- text: 'Propose products takes a brief, such as "a candle studio: hand-poured soy candles in 8 oz and 16 oz jars, and wax melts", and proposes up to twelve products, usually six or more unless your brief says how many: each with a name, type, description, tags, options, a search listing and a sentence saying what its photo should show.\nReview the table, untick any you do not want, and press Create drafts. Each product is created as a draft:\n- Its price is left empty, and the table marks it Set a price. The product editor will not save the product until every variant has a price, and a product with an empty price is never sold.\n- It has no photo, and the table marks it Needs a photo with the suggested shot. Nothing is uploaded or linked for you.\n- Nothing is on your storefront until you price it and set it to Active.\nA proposed product with the same name as one already in your catalog is left out.'
782
+ text: 'On the products page, press Create with AI beside Add product (and beside Add your first product while the catalog is empty), or Propose products in Build your catalog with AI — both open the same brief. Propose products takes a brief, such as "a candle studio: hand-poured soy candles in 8 oz and 16 oz jars, and wax melts", and proposes up to twelve products, usually six or more unless your brief says how many: each with a name, type, description, tags, options, a search listing and a sentence saying what its photo should show.\nReview the table, untick any you do not want, and press Create drafts. Each product is created as a draft:\n- Its price is left empty, and the table marks it Set a price. The product editor will not save the product until every variant has a price, and a product with an empty price is never sold.\n- It has no photo, and the table marks it Needs a photo with the suggested shot. Nothing is uploaded or linked for you.\n- Nothing is on your storefront until you price it and set it to Active.\nA proposed product with the same name as one already in your catalog is left out.'
601
783
  },
602
784
  {
603
785
  path: '/ai/products-with-ai',
@@ -1472,7 +1654,7 @@ export const DOCS_SECTION_INDEX = [
1472
1654
  title: 'Reusable components',
1473
1655
  heading: '',
1474
1656
  anchor: '',
1475
- text: 'Reusable components\nBuild something once — a card, a call-to-action, a footer block — and reuse it everywhere as a reusable component.\nAn instance is not a copy. It grafts the source at render time, so editing the component updates every page that places it. Change a font size once and the whole site follows.\nA component is content you repeat inside a page. If what you want is the frame around the page — header, navigation, footer — that is a layout, not a component. And if you want a starting point you copy once, with no live link back to the source, that is a template.\nPlan availability Starter and above. On Free, promoting an element answers "Reusable components require a Starter plan — see Billing to upgrade." There is no cap on how many components a site can have.'
1657
+ text: 'Reusable components\nBuild something once — a card, a call-to-action, a footer block — and reuse it everywhere as a reusable component.\nAn instance is not a copy. It grafts the source at render time, so editing the component updates every page that places it. Change a font size once and the whole site follows.\nA component is content you repeat inside a page. If what you want is the frame around the page — header, navigation, footer — that is a layout, not a component. And if you want a starting point you copy once, with no live link back to the source, that is a template.\nPlan availability One per site on Free; unlimited on Starter and above. The site\'s Components page shows how many a site has used, for example 0/1 components on your plan on Free. The limit applies when you create, promote, duplicate or install a component: at the limit, the next one is refused with "Your plan includes 1 reusable component — upgrade in Billing for more." A deleted component frees its place. A site that holds more components than its plan includes, for example after moving to Free, keeps every one of them, and they keep rendering.'
1476
1658
  },
1477
1659
  {
1478
1660
  path: '/building-sites/besigner/reusable-components',
@@ -1535,7 +1717,7 @@ export const DOCS_SECTION_INDEX = [
1535
1717
  title: 'Reusable components',
1536
1718
  heading: 'Duplicate',
1537
1719
  anchor: '#duplicate',
1538
- text: 'To start a new component from an existing one, choose Duplicate… in its row menu on the Components page, or More → Duplicate on its detail page. The copy carries the definition, its properties and the latest saved version, under the name you give it. It has no instances: every page keeps pointing at the original, and you place the copy where you want it. Duplicating needs the same plan as creating a component.'
1720
+ text: 'To start a new component from an existing one, choose Duplicate… in its row menu on the Components page, or More → Duplicate on its detail page. The copy carries the definition, its properties and the latest saved version, under the name you give it. It has no instances: every page keeps pointing at the original, and you place the copy where you want it. A copy counts toward your plan\'s components per site, the same as creating one.'
1539
1721
  },
1540
1722
  {
1541
1723
  path: '/building-sites/besigner/reusable-components',
@@ -1780,7 +1962,7 @@ export const DOCS_SECTION_INDEX = [
1780
1962
  title: 'Bindings, Variables & Functions',
1781
1963
  heading: 'No-code functions',
1782
1964
  anchor: '#no-code-functions',
1783
- text: 'Build functions in the in-editor function builder with a safe evaluator — no arbitrary code execution. Compose variables and other functions, and call them inline with {{fn:name(args)}}.\nA function is parameters in, numbered if / then / otherwise steps, and one value out. Inside a step, an expression can use:\n- + - / and parentheses, on numbers; + also joins text.\n- Any site variable, by its name. A function that prices a plan can read extrasiteprice directly, so changing the variable changes every page and every calculator that uses it. A function can read a variable and never set one, and a parameter or local variable with the same name wins.\n- A dictionary variable\'s members, as name.member. Keep one dictionary per plan — {"name": "Pro", "annual": 39, "sites": 3} — and read planpro.annual. A text variable inside the function can hold a copy of one (chosen = planpro), so the function can pick a plan and then read chosen.sites.\n- These built-ins: min(a, b, …), max(a, b, …), round(value, places), floor(value), ceil(value), abs(value), and format(value, places), which writes a number with thousands separators — \'$\' + format(1396) is $1,396.\nThere are no loops and no way to add a built-in, which is what keeps the evaluator safe to run on a page.\nParameters a visitor can answer\nWhen a function is placed on a page in a Function Widget, each parameter becomes an input. Under What visitors see in the function builder, give a parameter a Label (instead of its identifier), a value it Starts as, and Choices written as value: Label, value: Label. A parameter with choices is asked as a list, a number as a number box, and a true/false as a switch.\nA widget runs in the visitor\'s browser, so the function\'s definition is part of the page, along with the site variables that function na'
1965
+ text: 'Build functions in the in-editor function builder with a safe evaluator — no arbitrary code execution. Compose variables and other functions, and call them inline with {{fn:name(args)}}.\nA function is parameters in, numbered if / then / otherwise steps, and one value out. Inside a step, an expression can use:\n- + - / and parentheses, on numbers; + also joins text.\n- Any site variable, by its name. A function that prices a plan can read extrasiteprice directly, so changing the variable changes every page and every calculator that uses it. A function can read a variable and never set one, and a parameter or local variable with the same name wins.\n- A dictionary variable\'s members, as name.member. Keep one dictionary per plan — {"name": "Pro", "annual": 39, "sites": 3} — and read planpro.annual. A text variable inside the function can hold a copy of one (chosen = planpro), so the function can pick a plan and then read chosen.sites.\n- These built-ins: min(a, b, …), max(a, b, …), round(value, places), floor(value), ceil(value), abs(value), and format(value, places), which writes a number with thousands separators — \'$\' + format(1396) is $1,396.\nThere are no loops and no way to add a built-in, which is what keeps the evaluator safe to run on a page.\nCreate with AI on the Functions and Variables cards writes one from a description, and a saved function\'s editor can explain, change or fix it — each opens unsaved in the editor. See Functions and variables with AI.\nParameters a visitor can answer\nWhen a function is placed on a page in a Function Widget, each parameter becomes an input. Under What visitors see in the function builder, give a parameter a Label (instead of its identifier), a value it Starts as, and Choices written as value: Label, value: Label. A parameter with choi'
1784
1966
  },
1785
1967
  {
1786
1968
  path: '/building-sites/bindings/overview',
@@ -1808,7 +1990,7 @@ export const DOCS_SECTION_INDEX = [
1808
1990
  title: 'Generate a reusable component with Aglyn AI',
1809
1991
  heading: '',
1810
1992
  anchor: '',
1811
- text: 'Generate a reusable component with Aglyn AI\nAglyn AI makes a reusable component two ways: from a brief, such as "a testimonial card with the customer\'s name, their role, their quote and a photo," or from a section you already have on a page. Either way you get one component built the way you would build it yourself: the elements, and a property for each value that changes from one page to the next, already bound to the element that shows it.\nAvailability Aglyn AI build jobs are released gradually, and need the Generate with AI permission. Reusable components come with the Starter plan and above: on a plan without them, the job says so before it starts, and spends nothing.'
1993
+ text: 'Generate a reusable component with Aglyn AI\nAglyn AI makes a reusable component two ways: from a brief, such as "a testimonial card with the customer\'s name, their role, their quote and a photo," or from a section you already have on a page. Either way you get one component built the way you would build it yourself: the elements, and a property for each value that changes from one page to the next, already bound to the element that shows it.\nAvailability Aglyn AI build jobs are released gradually, and need the Generate with AI permission. Free includes one reusable component per site, and Starter and above include as many as you need: on a site already holding the components its plan includes, the job says so before it starts, and spends nothing.'
1812
1994
  },
1813
1995
  {
1814
1996
  path: '/building-sites/components/generate-a-component-with-aglyn-ai',
@@ -1822,7 +2004,7 @@ export const DOCS_SECTION_INDEX = [
1822
2004
  title: 'Generate a reusable component with Aglyn AI',
1823
2005
  heading: 'From a section on your page',
1824
2006
  anchor: '#from-a-section-on-your-page',
1825
- text: 'A section you have already built and want to reuse does not need describing: select it in the Besigner and use Make a reusable component with AI, under the element\'s own settings in the Attributes panel. Name the component, and Aglyn AI reads the section and suggests which of its values each page should be able to change.\nThe suggestion is shown before anything happens, with what every page will be able to set. The kinds, the pairings and the Hide … rule above are the same ones, except that a section\'s icon stays part of the section rather than becoming an Icon property.\nApply then does what Save as reusable component does, with the properties already in place:\n1. the component is saved to your library, with each suggested value replaced by its property;\n2. the section on your page is swapped for one that follows the component.\nEach property\'s default is the value that was on the page, so the page looks exactly as it did a moment before — the section now follows the component instead of being a copy of it. A Hide … property starts as No, because the part it hides is on the page.\nThe swap is an unsaved change on the version you have open, and one undo takes it back. Nothing is published, and on the version your live site shows, the Besigner asks you to make a new version first. If the component cannot be saved — a plan without reusable components, for instance — nothing on your page changes at all.\nPick the section, not the page Save the part you want to repeat. Aglyn AI declines a selection that is the whole page, one carrying the page\'s main region, or one with more than one top-level heading, because a component is placed inside pages rather than being one.'
2007
+ text: 'A section you have already built and want to reuse does not need describing: select it in the Besigner and use Make a reusable component with AI, under the element\'s own settings in the Attributes panel. Name the component, and Aglyn AI reads the section and suggests which of its values each page should be able to change.\nThe suggestion is shown before anything happens, with what every page will be able to set. The kinds, the pairings and the Hide … rule above are the same ones, except that a section\'s icon stays part of the section rather than becoming an Icon property.\nApply then does what Save as reusable component does, with the properties already in place:\n1. the component is saved to your library, with each suggested value replaced by its property;\n2. the section on your page is swapped for one that follows the component.\nEach property\'s default is the value that was on the page, so the page looks exactly as it did a moment before — the section now follows the component instead of being a copy of it. A Hide … property starts as No, because the part it hides is on the page.\nThe swap is an unsaved change on the version you have open, and one undo takes it back. Nothing is published, and on the version your live site shows, the Besigner asks you to make a new version first. If the component cannot be saved — a site already holding the components its plan includes, for instance — nothing on your page changes at all.\nPick the section, not the page Save the part you want to repeat. Aglyn AI declines a selection that is the whole page, one carrying the page\'s main region, or one with more than one top-level heading, because a component is placed inside pages rather than being one.'
1826
2008
  },
1827
2009
  {
1828
2010
  path: '/building-sites/components/generate-a-component-with-aglyn-ai',
@@ -2242,7 +2424,7 @@ export const DOCS_SECTION_INDEX = [
2242
2424
  title: 'Generate a page from a prompt',
2243
2425
  heading: 'Review the plan',
2244
2426
  anchor: '#review-the-plan',
2245
- text: 'The job proposes a plan before it builds anything: the layout the page renders in, the components and forms it places, anything it needs to create first, the page\'s address and search title, and its sections from top to bottom. The window shows it when it is ready, with what the whole job is estimated to use: choose Confirm plan to build it, or Cancel job. Open AI jobs follows the job in the Assist panel instead, and the AI chip in the top bar says AI · plan ready while the plan waits for you. When the page is built, Open the draft page opens it in the editor.\nWhen the page needs something your site does not have yet, such as a layout, a reusable component for cards that repeat, or a form, the plan lists it, and confirming builds it first, in the same job, before the page that uses it. A plan only proposes what your workspace can create: what your plan includes and what your site has room for. Something a page job does not build, such as a page template or a dataset, is not offered for confirmation: the job stops before you confirm anything and tells you what to create first and where.\nOn a plan without reusable components, such as Free, the page is built from what that plan can make: a block that repeats, such as a row of service cards, is built into the page each time, in one section, and a form is part of the page, with its fields, collecting submissions into your inbox like any form.'
2427
+ text: 'The job proposes a plan before it builds anything: the layout the page renders in, the components and forms it places, anything it needs to create first, the page\'s address and search title, and its sections from top to bottom. The window shows it when it is ready, with what the whole job is estimated to use: choose Confirm plan to build it, or Cancel job. Open AI jobs follows the job in the Assist panel instead, and the AI chip in the top bar says AI · plan ready while the plan waits for you. When the page is built, Open the draft page opens it in the editor.\nWhen the page needs something your site does not have yet, such as a layout, a reusable component for cards that repeat, or a form, the plan lists it, and confirming builds it first, in the same job, before the page that uses it. A plan only proposes what your workspace can create: what your plan includes and what your site has room for. Something a page job does not build, such as a page template or a dataset, is not offered for confirmation: the job stops before you confirm anything and tells you what to create first and where.\nOn Free, which includes one reusable component per site and leaves it for you to spend, the page is built without one: a block that repeats, such as a row of service cards, is built into the page each time, in one section, and a form is part of the page, with its fields, collecting submissions into your inbox like any form.'
2246
2428
  },
2247
2429
  {
2248
2430
  path: '/building-sites/screens-and-layouts/generate-a-page',
@@ -3103,7 +3285,21 @@ export const DOCS_SECTION_INDEX = [
3103
3285
  title: 'Edit your theme',
3104
3286
  heading: 'Set colors and fonts',
3105
3287
  anchor: '#set-colors-and-fonts',
3106
- text: '- Choose your palette and typography.\n- Pick any Google font. Your published site serves it from its own address — the font rules are part of the page and the files come from your site with a long cache, so text never waits on a stylesheet from Google, and visitors\' browsers never contact Google for your fonts. The one or two fonts the top of the page uses start loading with the page itself. Text shows in a fallback font for the moment a font file is still arriving, never as blank space.\n- Configure both light and dark schemes. Published sites follow the visitor\'s system scheme (or their choice in the theme mode switcher); anything you leave unset under Dark comes from the platform\'s default dark palette, so a site goes dark without a dark design of its own.\n- Dark scheme — set it to Off when your content only reads well in light: every visitor stays on light and the theme mode switcher is hidden on published pages.'
3288
+ text: '- Choose your palette and typography.\n- Pick any Google font with the font browser. Your published site serves it from its own address: the font rules are part of the page and the files come from your site with a long cache, so text never waits on a stylesheet from Google, and visitors\' browsers never contact Google for your fonts.\n- Your site loads each font at the weights your text styles use, including the bold headings, so a heading never shows a stand-in weight. Each font comes either as one file per weight or as one file holding every weight, whichever is smaller.\n- The fonts for the body text and the main heading start loading with the page. Until a font arrives, text shows in a fallback that is sized to match it, so nothing moves when the font swaps in.\n- A site that picks no font uses the visitor\'s system font and loads no font files.\n- Configure both light and dark schemes. Published sites follow the visitor\'s system scheme (or their choice in the theme mode switcher); anything you leave unset under Dark comes from the platform\'s default dark palette, so a site goes dark without a dark design of its own.\n- Dark scheme — set it to Off when your content only reads well in light: every visitor stays on light and the theme mode switcher is hidden on published pages.'
3289
+ },
3290
+ {
3291
+ path: '/building-sites/theme-builder/edit-your-theme',
3292
+ title: 'Edit your theme',
3293
+ heading: 'Fonts',
3294
+ anchor: '#fonts',
3295
+ text: 'The Fonts control in the Typography card sets two things: the font for your body text and, if you want one of their own, the font for your headings. Each is shown in your own site\'s name and words, so you judge a font by how it will actually read.\nPress Change beside either one to open the font browser:\n- Every Google font, most popular first. Search by name, or narrow the list with the Sans serif, Serif, Display, Handwriting and Monospace chips. Each font in the list previews your site\'s name in that font as it scrolls into view.\n- Theme default (for body text) keeps the font each visitor\'s device already has, which costs nothing to download. Same as body text (for headings) sets headings in the body font, in each heading\'s own weight.\n- Pick a font to see your heading and a paragraph in it, then choose the styles to load — the weights, and italics for headings. Body text always loads its italic, so emphasis is a true italic.\n- Use for body text or Use for headings puts the font in the editor. Nothing changes on your site until you press Save, and Discard changes takes it back.\nDownload size\nThe badge beside your fonts (for example ≈ 38 KB · 2 files) is what a visitor downloads for them: the Latin files your text styles and italics use, measured the way your published pages load them — one file per weight, or one variable file holding every weight, whichever is smaller. Your headings and other text styles load the weights they use as well, matched to the nearest one the font has, so they count too. 0 KB means your site uses the visitor\'s own system font. In the browser, This font is the font you are looking at and All your fonts is the total with it in place.\nFewer fonts and fewer weights load faster. One family with a regular and a bold weight is often all a site need'
3296
+ },
3297
+ {
3298
+ path: '/building-sites/theme-builder/edit-your-theme',
3299
+ title: 'Edit your theme',
3300
+ heading: 'Upload your own font',
3301
+ anchor: '#upload-your-own-font',
3302
+ text: 'Use a font that is not on Google Fonts (your brand\'s typeface, for example) from Your own fonts, at the bottom of the Typography card.\n1. Drop one or more font files on the box, or click it to choose them. Each file can be a WOFF2, WOFF, TTF or OTF file of up to 4 MB. Upload each weight and style (Regular, Bold, Italic) as its own file; a variable font is one file for every weight.\n2. Each file is checked before anything is stored. You see the family, weight and style read from the file, what its license allows, and its size before and after.\n3. Choose Use for body text or Use for headings from the family\'s ⋮ menu, then Save the theme. Until you save, the upload changes only your draft.\nWhat happens to the file:\n- The license is read from the file. A font carries embedding permissions set by its maker. One marked as not embeddable (a restricted license), or as bitmap-only, is refused, because it cannot be used on a website. One marked for viewing and printing only is installed with a warning: many such licenses still exclude websites, so check yours before you publish. By uploading a font you confirm that its license lets you use it on your website. The check reads the font\'s own flags; it cannot see the license you bought.\n- It is converted for the web. The file is stored as WOFF2 and trimmed to the scripts it covers among Latin, Latin Extended, Cyrillic, Greek and Vietnamese, which usually makes it a fraction of its original size. A font whose license asks for it to be embedded whole is converted without trimming. A variable font keeps all of its weights.\n- It lives in your media library, and counts toward your storage like any other file. Uploading a new file for the same family, weight and style replaces the one already there rather than adding a second copy, and yo'
3107
3303
  },
3108
3304
  {
3109
3305
  path: '/building-sites/theme-builder/edit-your-theme',
@@ -3173,7 +3369,7 @@ export const DOCS_SECTION_INDEX = [
3173
3369
  title: 'Bookings & Scheduling',
3174
3370
  heading: 'Set up bookings',
3175
3371
  anchor: '#set-up-bookings',
3176
- text: '1. Define services (what can be booked, duration, price).\n2. Configure availability — the windows when slots are offered.\n3. Add the booking widget to a page as a canvas element.\nPrice varies, free estimate, or contact for price {#price-labels}\nA service that is quoted at the job doesn\'t need a price. In the service\'s dialog, Show the price as picks how the widget states it:\n- The price (the default): the widget shows the price, and a priced service is paid through Stripe when it\'s booked.\n- Price varies, Free estimate or Contact for price: the widget shows that label instead, and the service books with no charge, like an estimate appointment. Any price typed in the dialog is neither shown nor charged, and you quote the visitor afterwards.\nA labeled service needs no connected Stripe account, because nothing is charged.\nAsking for a phone number and an address {#phone-and-address}\nThe booking widget always asks for a name and an email. A service can also ask for a phone number and an address — the place the job is, for a service done on site. Set each one in the service\'s dialog under Booking form:\n- Don\'t ask (the default) — the field does not appear.\n- Optional — the field appears and the visitor may leave it empty.\n- Required — the visitor cannot confirm the booking without it.\nThe booking is checked again when it arrives, so a required field cannot be skipped. A phone number has to look like one: a US or Canadian number is stored in international form (+15125550107), and a number written another country\'s way is kept as typed.\nWhat the visitor gives shows:\n- on the booking in Upcoming bookings;\n- in the New booking notification the site\'s managers get, by email too if they have email notifications on — for paid bookings as well, once the payment clears;\n- on the meet'
3372
+ text: '1. Define services (what can be booked, duration, price).\n2. Configure availability — the windows when slots are offered.\n3. Add the booking widget to a page as a canvas element.\nDraft services {#draft-services}\nA service is either active — it takes bookings — or a draft: set up, and offered nowhere. A draft is left out of the booking widget\'s list, shows no open times, and a booking for it is refused, even through a link that names it.\n- A service you add with Add service is active as soon as you save it.\n- A service set up for you elsewhere in Aglyn, rather than added on this page, starts as a draft, so nothing goes live before you have looked at it. If no price was given, it is set to Contact for price.\n- On the Bookings page a draft carries a Draft label and an Activate button. Activate puts it on your site straight away.\n- Deactivate turns an active service back into a draft: it stops taking bookings without being deleted, and the bookings it already has stay.\nA draft counts toward your plan\'s service allowance, like an active service.\nPrice varies, free estimate, or contact for price {#price-labels}\nA service that is quoted at the job doesn\'t need a price. In the service\'s dialog, Show the price as picks how the widget states it:\n- The price (the default): the widget shows the price, and a priced service is paid through Stripe when it\'s booked.\n- Price varies, Free estimate or Contact for price: the widget shows that label instead, and the service books with no charge, like an estimate appointment. Any price typed in the dialog is neither shown nor charged, and you quote the visitor afterwards.\nA labeled service needs no connected Stripe account, because nothing is charged.\nAsking for a phone number and an address {#phone-and-address}\nThe booking widget always ask'
3177
3373
  },
3178
3374
  {
3179
3375
  path: '/commerce-and-bookings/bookings/overview',
@@ -3215,7 +3411,7 @@ export const DOCS_SECTION_INDEX = [
3215
3411
  title: 'Product catalog',
3216
3412
  heading: 'Products, options, and variants',
3217
3413
  anchor: '#products-options-and-variants',
3218
- text: 'A product is what you manage; a variant is what a customer actually buys. Products define up to 3 options (like Size or Color, each with up to 25 values), and the products hub expands them into a variants matrix — up to 100 variants per product, each with its own SKU, barcode, price, compare-at price, weight, image, and inventory count.\n- Types: physical (shippable), digital (delivered as downloads), or service.\n- Status: draft (invisible to visitors), active, or archived.\n- Pricing: a variant with a compare-at price above its price shows a sale badge on storefront blocks.\n- Inventory: leave blank for untracked, 0 means sold out — the same semantics the original product block used. Stock is not tracked on a digital or service subscription-only product: nothing decrements it, on the first charge or on any renewal, so the field is disabled there. A physical subscription tracks normally — every paid cycle decrements one unit per box shipped — and Both — buyer chooses keeps tracking on the one-time sales.\nProducts created with the earlier single-price product block are lifted into this model automatically as a single default variant — nothing breaks and no migration step is needed.'
3414
+ text: 'A product is what you manage; a variant is what a customer actually buys. Products define up to 3 options (like Size or Color, each with up to 25 values), and the products hub expands them into a variants matrix — up to 100 variants per product, each with its own SKU, barcode, price, compare-at price, weight, image, and inventory count.\n- Types: physical (shippable), digital (delivered as downloads), or service.\n- Status: draft (invisible to visitors), active, or archived. A product created for you rather than added in the editor — a proposed product, for one — starts as a draft with no photo, and its price stays empty unless one was given. It counts toward your plan\'s product allowance like any other product.\n- Pricing: a variant with a compare-at price above its price shows a sale badge on storefront blocks.\n- Inventory: leave blank for untracked, 0 means sold out — the same semantics the original product block used. Stock is not tracked on a digital or service subscription-only product: nothing decrements it, on the first charge or on any renewal, so the field is disabled there. A physical subscription tracks normally — every paid cycle decrements one unit per box shipped — and Both — buyer chooses keeps tracking on the one-time sales.\nProducts created with the earlier single-price product block are lifted into this model automatically as a single default variant — nothing breaks and no migration step is needed.'
3219
3415
  },
3220
3416
  {
3221
3417
  path: '/commerce-and-bookings/commerce/catalog',
@@ -3257,14 +3453,98 @@ export const DOCS_SECTION_INDEX = [
3257
3453
  title: 'Product catalog',
3258
3454
  heading: 'Google Merchant Center feed',
3259
3455
  anchor: '#merchant-center-feed',
3260
- text: 'Your catalog is also published as a product feed for Google Merchant Center. The address is on the Store settings card under Commerce → Settings: a read-only Google Merchant Center feed URL field with a Copy feed URL button beside it.\nIn Merchant Center, add it under Products → Feeds as a scheduled fetch. Merchant Center then re-reads the URL on the schedule you set there, so catalog changes reach it without another upload.\nWhat the feed contains:\n- One item per active product. Draft, archived, and deleted products never appear. Items are per product, not per variant — the price is the lowest price across the product\'s variants.\n- Per item: the product id, name, description (its name again if the description is empty), a link to /products/{slug} on your store, the product\'s first image if it has one, the price in USD, an availability value, and the condition new.\n- Availability is outofstock when a tracked stock count has reached zero and the product does not allow backorders. Everything else — including untracked stock — is instock.\n- Up to 500 products. A larger catalog is not fully represented in the feed.\nTwo things worth knowing before you submit it:\n- Use the URL the card gives you. Each item\'s link is built from the address the feed was requested on, so submitting the wrong one puts the wrong domain on every product in Merchant Center.\n- The URL appears once the site has an address — a subdomain or a custom domain. Until then the card says so rather than showing a partial URL.\nThe feed needs no credentials to read, and it carries only what your storefront already shows publicly. Responses are cached for an hour, so a price or stock change can take that long to appear in a fetch.'
3456
+ text: 'Your catalog is published as a product feed for Google Merchant Center, and for Meta, TikTok, Pinterest, Snapchat and Microsoft Shopping too. Each channel has its own feed address and setup steps under Products → Settings → Sales channels; see Sales channels.'
3261
3457
  },
3262
3458
  {
3263
3459
  path: '/commerce-and-bookings/commerce/catalog',
3264
3460
  title: 'Product catalog',
3265
3461
  heading: 'Related',
3266
3462
  anchor: '#related',
3267
- text: '- Commerce overview\n- SEO — products emit structured data and join the sitemap automatically.'
3463
+ text: '- Sales channels\n- Commerce overview\n- SEO — products emit structured data and join the sitemap automatically.'
3464
+ },
3465
+ {
3466
+ path: '/commerce-and-bookings/commerce/order-notifications',
3467
+ title: 'Order emails & status page',
3468
+ heading: '',
3469
+ anchor: '',
3470
+ text: 'Order emails & status page\nYour customers hear about their order at every step, without you doing anything: when it\'s paid, each time part of it ships, when it\'s delivered, when you refund it and when you cancel it. Every one of these emails links to a private order status page on your site where the customer can see the order, its shipments and their tracking.'
3471
+ },
3472
+ {
3473
+ path: '/commerce-and-bookings/commerce/order-notifications',
3474
+ title: 'Order emails & status page',
3475
+ heading: 'What your customers get',
3476
+ anchor: '#customer-emails',
3477
+ text: '| When | Email | What it says |\n| -- | -- | -- |\n| An order is paid | Order receipt | The items, the total, any license keys and download links, and your receipt footer. Sent for checkout and Buy buttons, for payment links you send from a draft order, and for register sales when the customer gives an email. |\n| You ship part or all of an order | Order shipped | The items in that package, the carrier and tracking number with a tracking link, and how many items are still to ship. One email per package. |\n| You mark an order delivered | Order delivered | The order and its items. |\n| You refund an order | Order refunded | The amount, the items you refunded by name (if you picked any), and whether the order is now refunded in full. One email per refund. |\n| You cancel an order | Order canceled | The order and its items. Canceling doesn\'t refund a payment: refund first if the customer paid. |\nA dropship supplier who posts tracking for their part of an order sends the customer the same Order shipped email.\nEach email is sent once. If a payment confirmation arrives twice, or you click a button twice, the customer still gets one email. A second package or a second partial refund is a new email.\nRegister sales and orders with only digital or service items don\'t send a shipping or delivery email unless you add a tracking number.\nTracking links\nTracking links are built from the carrier you type when you fulfill: USPS, UPS, FedEx, DHL, Canada Post, Royal Mail and Australia Post are recognized, including spellings like "UPS Ground" or "Fed Ex". For any other carrier the email shows the carrier and tracking number without a link.\nTurning emails off\nAll five emails are on for every store. To turn one off, open Commerce → Settings → Customer notifications and switch it off. Switching th'
3478
+ },
3479
+ {
3480
+ path: '/commerce-and-bookings/commerce/order-notifications',
3481
+ title: 'Order emails & status page',
3482
+ heading: 'The order status page',
3483
+ anchor: '#order-status-page',
3484
+ text: 'Every order email links to /order-status on your site, with a private link for that one order. The page shows, in your site\'s header, footer and theme:\n- the order number and status, with a timeline from placed to delivered\n- each package, its carrier and tracking number, and a Track package button\n- the items, what\'s shipped so far, and the totals, refunds included\nCustomers don\'t need an account. The link only works for that order, and the page never shows the customer\'s email, phone or address, so a forwarded email reveals nothing the email didn\'t already say. Search engines are told not to index it.\nTo design the page yourself, create a page at /order-status and place the Order status element on it (under Commerce in the Besigner). Your page is used instead of the built-in one.'
3485
+ },
3486
+ {
3487
+ path: '/commerce-and-bookings/commerce/order-notifications',
3488
+ title: 'Order emails & status page',
3489
+ heading: 'Resend a receipt',
3490
+ anchor: '#resend-receipt',
3491
+ text: 'Open an order and click Resend receipt. The customer\'s email is filled in; change it to send the receipt somewhere else. The order\'s timeline records each send. To stop accidental floods, an order\'s receipt can be resent five times an hour.'
3492
+ },
3493
+ {
3494
+ path: '/commerce-and-bookings/commerce/order-notifications',
3495
+ title: 'Order emails & status page',
3496
+ heading: 'Text messages',
3497
+ anchor: '#text-messages',
3498
+ text: 'Rolling out Text messages for order updates aren\'t available yet. Until they are, every order notification is sent by email, and no option to text a customer appears anywhere in your console.\nWhen text messages are available, the Customer notifications settings get an Also send as texts switch, and Resend receipt can send by text. Customers can reply STOP to any text to stop receiving them. Receipts are texted right away; texts about shipping, delivery, refunds and cancellations that would arrive between 9 PM and 8 AM in your site\'s time zone are held until 8 AM.'
3499
+ },
3500
+ {
3501
+ path: '/commerce-and-bookings/commerce/order-notifications',
3502
+ title: 'Order emails & status page',
3503
+ heading: 'Related',
3504
+ anchor: '#related',
3505
+ text: '- Commerce overview\n- POS & reservations'
3506
+ },
3507
+ {
3508
+ path: '/commerce-and-bookings/commerce/orders-and-returns',
3509
+ title: 'Fulfillment, returns and webhooks',
3510
+ heading: '',
3511
+ anchor: '',
3512
+ text: 'Fulfillment, returns and webhooks\nWhat happens to an order after it is paid: shipping it, in one parcel or several; taking items back; printing its paperwork; and telling your other systems about it. Everything here is in the order\'s dialog on the Orders tab of the Products hub, and under Returns and Settings beside it.'
3513
+ },
3514
+ {
3515
+ path: '/commerce-and-bookings/commerce/orders-and-returns',
3516
+ title: 'Fulfillment, returns and webhooks',
3517
+ heading: 'Ship an order in parts',
3518
+ anchor: '#fulfillment',
3519
+ text: 'Fulfill… in the order\'s dialog opens the Fulfill items panel. Each line starts at the units still to ship; lower a quantity to send part of a line now and the rest later. Digital and service lines have nothing to ship and never hold an order open.\n- Carrier and Tracking number make the tracking link for USPS, UPS, FedEx, DHL, Canada Post, Royal Mail and Australia Post. For any other carrier, choose Other, type its name, and paste the Tracking link yourself.\n- Notify customer emails the buyer the shipment with its tracking link. Leave it off to record a shipment quietly.\n- The order reads Partially fulfilled until every unit that ships is out, then Fulfilled.\nEach shipment is listed in the dialog. Edit tracking corrects a carrier or a number; Cancel shipment puts its units back to be shipped again. Ticking orders in the list and choosing Mark as fulfilled ships every remaining unit of each.'
3520
+ },
3521
+ {
3522
+ path: '/commerce-and-bookings/commerce/orders-and-returns',
3523
+ title: 'Fulfillment, returns and webhooks',
3524
+ heading: 'Invoices and packing slips',
3525
+ anchor: '#invoices',
3526
+ text: 'Invoice in the order\'s dialog opens the order as a bill, ready to print: your business name, the date, who it is billed and shipped to, each line with its unit price, the subtotal, discount, shipping, tax and total, and anything refunded. Your store\'s receipt footer and terms address print at the foot. To keep a PDF, choose Save as PDF in the print dialog.\nPacking slip prints what goes in the box — the shipping address and each line\'s quantity, name, option and SKU — with no prices.'
3527
+ },
3528
+ {
3529
+ path: '/commerce-and-bookings/commerce/orders-and-returns',
3530
+ title: 'Fulfillment, returns and webhooks',
3531
+ heading: 'Returns',
3532
+ anchor: '#returns',
3533
+ text: 'A return is its own record beside the order: what is coming back and why, what you decided, the return label, what went back in stock, and the refund. Every return is listed under Returns in the Products hub, newest first; the Status filter shows one state at a time.\nHow a buyer asks {#buyer-requests}\nA buyer asks for a return themselves, from either of two places:\n- the Request a return link beside an order in their account on your store, when they are signed in;\n- the Request a return button on the order\'s status page — the View your order link in every order email — which needs no account. The button shows only while the return window is open and something on the order can still come back.\nBoth open the return page at /order-return in your site\'s header and footer. The page is unlisted, so search engines leave it out; to design your own, make a page at /order-return and place the Return request block on it. The buyer chooses how many of each item to send back and a reason for each — Arrived damaged, Wrong item, Not as described, Size or fit, No longer needed or Other — and can add a note. Only items that have shipped can be returned, and never more than were bought or are already coming back. You and the site\'s managers are told by email and in the console\'s notifications.\nUnder Settings → Returns:\n- Accept return requests online — turn it off to take returns only by contact. You can still start a return for a buyer from the order.\n- Return window in days — counted from the last shipment, or from the order date for an order with nothing to ship. 0 to 365.\n- Returnable product types — physical products only, by default.\nRun a return {#run-a-return}\nOpen a return from the list, or from the Returns section of its order\'s dialog, where Start return opens one for the buye'
3534
+ },
3535
+ {
3536
+ path: '/commerce-and-bookings/commerce/orders-and-returns',
3537
+ title: 'Fulfillment, returns and webhooks',
3538
+ heading: 'Order webhooks',
3539
+ anchor: '#order-webhooks',
3540
+ text: 'An order webhook posts each order event to an address you choose, as it happens: a warehouse system, an ERP, a spreadsheet script. Add them under Settings → Order webhooks in the Products hub. Managing webhooks needs the admin role and organization-wide membership, the same as refunds.\nAdd endpoint asks for:\n- Endpoint URL — an https:// address on a public server. Redirects are not followed, so give the final address.\n- Events — any of the events below.\nWhen you add an endpoint, its signing secret is shown once. Copy it into your endpoint\'s settings; Roll secret makes a new one if it is lost. A store can keep 10 endpoints. Pause stops deliveries to one without deleting it, and Send test event posts a webhook.test event now.\n| Event | When |\n| order.paid | An order was paid: online, buy-now, a payment link, a POS sale or a subscription renewal. |\n| order.fulfilled | A shipment was recorded, once per shipment. |\n| order.delivered | The order was marked delivered. |\n| order.refunded | Money went back to the buyer, once per refund, including a refund made in the Stripe Dashboard. |\n| order.cancelled | The order was canceled. |\n| return.requested | A buyer asked for a return, or you opened one. |\n| return.approved | You approved a return, or opened one yourself. |\n| return.declined | You declined a return request. |\n| return.received | The returned items arrived. |\n| return.refunded | A return was refunded. |\nWhat your endpoint receives\nA POST with a JSON body:\ndata.order is the order in the same shape the API returns for GET /v1/sites/{siteId}/orders/{orderId}. Money is in whole cents. Three headers come with it:\n| Header | What it holds |\n| Aglyn-Event | The event, e.g. order.paid. |\n| Aglyn-Event-Id | The event\'s id. It is the same on every retry, so store it and ignore a'
3541
+ },
3542
+ {
3543
+ path: '/commerce-and-bookings/commerce/orders-and-returns',
3544
+ title: 'Fulfillment, returns and webhooks',
3545
+ heading: 'Related',
3546
+ anchor: '#related',
3547
+ text: '- Commerce overview\n- Commerce end to end'
3268
3548
  },
3269
3549
  {
3270
3550
  path: '/commerce-and-bookings/commerce/overview',
@@ -3306,14 +3586,21 @@ export const DOCS_SECTION_INDEX = [
3306
3586
  title: 'Commerce',
3307
3587
  heading: 'Orders',
3308
3588
  anchor: '#orders',
3309
- text: 'Every paid checkout becomes an order with a sequential number, line-item snapshots, totals, and a timeline:\n- Statuses: pending → paid → fulfilled (or partially) → delivered, with cancel/refund exits guarded by a status machine. The seven of them, and the labels the console shows, are in Statuses and channels.\n- Fulfill with tracking, print packing slips, add internal notes.\n- Refunds (full or partial) go through Stripe and reverse the platform fee. Refunding needs the admin role and organization-wide membership — a workspace owner or admin, or a member given access to every site. A collaborator invited to this one site is an admin of the site, which is enough to run the till and fulfill orders but not to send money back out of the business.\n- Chargebacks are shown apart from refunds. When a shopper disputes a charge with their bank, the order gets a Chargeback open badge and the list warns you with the date Stripe needs your evidence by — answer it in the Stripe dashboard, because an unanswered dispute is decided for the shopper. If the dispute is lost the money is reversed, the order reads Charged back rather than Refunded, and the buyer loses the downloads, membership and verified-purchase review a refund would have withdrawn. A dispute you win reverses nothing. Filter the list by Disputes to find either.\n- Draft orders: build an order in the console and send the buyer a payment link (Shopify parity). Requires an active plan with commerce — see the note below.\nThe Orders page {#orders-screen}\nOpen your site\'s Products hub and choose the Orders tab. Before your first sale the tab is an invitation rather than a table: it explains where orders come from and offers Draft order, so you can invoice a customer you already have. The table and Export orders appear once there '
3589
+ text: 'Every paid checkout becomes an order with a sequential number, line-item snapshots, totals, and a timeline:\n- Statuses: pending → paid → fulfilled (or partially) → delivered, with cancel/refund exits guarded by a status machine. The seven of them, and the labels the console shows, are in Statuses and channels.\n- Fulfill with tracking, in one shipment or several, print packing slips and invoices, and add internal notes — see Fulfillment, returns and webhooks.\n- Ship with the tools you already use: ShipStation imports your orders and sends each shipment back, ShippingEasy receives each order as it is paid and sends each label back, and Pirate Ship, Shippo or EasyPost work through a spreadsheet out and a file of tracking numbers back.\n- Returns: buyers ask from their account or the order-status page, and you approve, receive with restock and refund — see Returns. Order webhooks send each order event to your own systems — see Order webhooks.\n- Refunds (full or partial) go through Stripe and reverse the platform fee. Refunding needs the admin role and organization-wide membership — a workspace owner or admin, or a member given access to every site. A collaborator invited to this one site is an admin of the site, which is enough to run the till and fulfill orders but not to send money back out of the business.\n- Chargebacks are shown apart from refunds. When a shopper disputes a charge with their bank, the order gets a Chargeback open badge and the list warns you with the date Stripe needs your evidence by — answer it in the Stripe dashboard, because an unanswered dispute is decided for the shopper. If the dispute is lost the money is reversed, the order reads Charged back rather than Refunded, and the buyer loses the downloads, membership and verified-purchase review a refun'
3590
+ },
3591
+ {
3592
+ path: '/commerce-and-bookings/commerce/overview',
3593
+ title: 'Commerce',
3594
+ heading: 'Payment methods',
3595
+ anchor: '#payment-methods',
3596
+ text: 'Settings → Payment methods chooses what shoppers may pay with besides a card. Cards are always on. Every other method is on unless you turn it off, except stablecoins, which you turn on. Stripe shows a method only on orders it suits: the right currency, an amount inside its limits, and a shopper in a country it serves.\n| Method | What the shopper needs | Limits |\n| Apple Pay | Safari on a Mac, iPhone or iPad with a card in Apple Wallet | Same as cards |\n| Google Pay | Chrome or an Android device with a card in Google Pay | Same as cards |\n| Link | A card or bank saved with Link | Same as cards |\n| Klarna | A US shopper paying in USD | From $10 |\n| Afterpay | A US shopper paying in USD | $1 to $4,000, one-time purchases only |\n| Affirm | A US shopper paying in USD | $50 to $30,000, one-time purchases only |\n| Cash App Pay | A US shopper with Cash App | USD only |\n| Amazon Pay | An Amazon account with a saved card | USD only |\n| Stablecoins | A crypto wallet holding USDC or another supported stablecoin | USD only, up to $10,000 |\nThe card only lists the methods the platform offers. A method missing from your card is not available for storefronts yet. Anyone who manages the store can read the card; only a site admin can change it.\nWhat each chip means. Buy-now-pay-later, Cash App Pay, Amazon Pay and stablecoins also need Stripe to enable them on your payout account. Saving the card asks Stripe for that. Stripe is reviewing means it is still checking, and Stripe needs more details means Stripe wants more information. The organization owner presses Finish in Stripe on that method to give it. A method Stripe has not enabled on your account may not be offered to shoppers.\nApple Pay needs your domain registered with Stripe. Aglyn registers your custom domain when you connect it'
3310
3597
  },
3311
3598
  {
3312
3599
  path: '/commerce-and-bookings/commerce/overview',
3313
3600
  title: 'Commerce',
3314
3601
  heading: 'Shipping & taxes',
3315
3602
  anchor: '#shipping--taxes',
3316
- text: '- Shipping zones own countries (\'\' = rest of world); rates are flat, free-over-subtotal, or subtotal/weight tiers; optional local pickup.\n- Taxes: manual per-region rates (state beats country, VAT-style inclusive pricing supported) or Stripe Tax automatic calculation; products can be tax-exempt.\nLodging tax on reservations\nA stay is not goods. The sales-tax settings above configure a goods rate resolved against an address; occupancy (lodging/hotel) tax is a separate regime with its own rates, its own registration and its own return, so reservations do not use them.\nCommerce → Settings → Taxes → Lodging tax is where you set your own rate for it. It is off by default — leave it blank and reservations charge no lodging tax, exactly as before.\nWhen you set a rate, Aglyn adds it to the reservation charge as its own receipt line using the label you choose, and records the amount and the rate on the reservation. It is always your own rate: Stripe Tax cannot compute occupancy tax from a reservation session, so a store using Stripe Tax for goods still sets this one by hand.\nAglyn does not provide tax advice Aglyn applies the rate you enter and records what was charged. It does not determine whether lodging tax applies to you, at what rate, or where it should be paid. Confirm your obligations with a qualified tax professional.\nDeposits. A reservation usually charges a deposit rather than the whole stay, and the rate is applied to the amount actually charged — the deposit. Aglyn does not decide whether your jurisdiction wants occupancy tax on the full stay at booking, on the deposit, or at check-out. If tax is due on more than the deposit, collect the difference the way you collect the rest of the balance.\nStorefront sales tax\nAnalytics → Storefront sales tax shows what your store'
3603
+ text: '- Shipping zones own countries (\'\' = rest of world); rates are flat, free-over-subtotal, or subtotal/weight tiers; optional local pickup. See Shipping.\n- Taxes: manual per-region rates (state beats country, VAT-style inclusive pricing supported) or Stripe Tax automatic calculation; products can be tax-exempt.\nLodging tax on reservations\nA stay is not goods. The sales-tax settings above configure a goods rate resolved against an address; occupancy (lodging/hotel) tax is a separate regime with its own rates, its own registration and its own return, so reservations do not use them.\nCommerce → Settings → Taxes → Lodging tax is where you set your own rate for it. It is off by default — leave it blank and reservations charge no lodging tax, exactly as before.\nWhen you set a rate, Aglyn adds it to the reservation charge as its own receipt line using the label you choose, and records the amount and the rate on the reservation. It is always your own rate: Stripe Tax cannot compute occupancy tax from a reservation session, so a store using Stripe Tax for goods still sets this one by hand.\nAglyn does not provide tax advice Aglyn applies the rate you enter and records what was charged. It does not determine whether lodging tax applies to you, at what rate, or where it should be paid. Confirm your obligations with a qualified tax professional.\nDeposits. A reservation usually charges a deposit rather than the whole stay, and the rate is applied to the amount actually charged — the deposit. Aglyn does not decide whether your jurisdiction wants occupancy tax on the full stay at booking, on the deposit, or at check-out. If tax is due on more than the deposit, collect the difference the way you collect the rest of the balance.\nStorefront sales tax\nAnalytics → Storefront sales tax shows w'
3317
3604
  },
3318
3605
  {
3319
3606
  path: '/commerce-and-bookings/commerce/overview',
@@ -3327,7 +3614,7 @@ export const DOCS_SECTION_INDEX = [
3327
3614
  title: 'Commerce',
3328
3615
  heading: 'Related',
3329
3616
  anchor: '#related',
3330
- text: '- Product catalog\n- Billing & plans\n- Bookings & scheduling'
3617
+ text: '- Product catalog\n- Use ShipStation with Aglyn\n- Use ShippingEasy with Aglyn\n- Use Pirate Ship with Aglyn\n- Billing & plans\n- Bookings & scheduling'
3331
3618
  },
3332
3619
  {
3333
3620
  path: '/commerce-and-bookings/commerce/pos-and-reservations',
@@ -3348,7 +3635,42 @@ export const DOCS_SECTION_INDEX = [
3348
3635
  title: 'POS & reservations',
3349
3636
  heading: 'The register',
3350
3637
  anchor: '#the-register',
3351
- text: 'Open /{site}/pos in the console for a touch-first register. Pick which register you\'re on at the top of the panel (skipped automatically when you have only one):\n- Product grid — tap to add; products with variants show quick chips. The grid shows your first 500 active products by name; typing in the search box finds a product by the start of a word in its name across the whole catalog.\n- Barcode scanners — any keyboard-wedge scanner works: it types the code into the search box and presses Enter, which adds the exact SKU/barcode match. No drivers or pairing needed.\n- Payments — cash (with change calculation), card via QR (the customer scans and pays on their phone; the sale completes automatically), or charge to room for checked-in reservation guests. Stripe Terminal readers can replace the QR step later without changing the flow.\n- Receipts print through the browser\'s print dialog — any receipt printer with a system print driver works. Set the paper size to your roll width once and the browser remembers it.\nPOS sales create normal orders tagged pos, decrement the same inventory as your online store (per location if you use locations), and appear in the orders list under the channel filter.\nPlatform fees at the register\nYour plan\'s platform fee is charged on the sale, not on how it was paid — the rate is the same whether the customer hands you cash, scans the QR, or charges it to their room. What differs is only how it reaches us:\n| Tender | How the fee is collected |\n| Card (QR) | Deducted from your Stripe payout for that sale |\n| Cash | No payout to deduct from — added to your next monthly invoice |\n| Charge to room | Same as cash: added to your next monthly invoice |\nThe customer never pays the fee, and the amount Due on the register is the same on every tender. On pl'
3638
+ text: 'Open /{site}/pos in the console for a touch-first register. Pick which register you\'re on at the top of the panel (skipped automatically when you have only one):\n- Product grid — photo tiles with the price, a stock note when only a few are left or none, and a count of how many are already in the basket. Tap a product to add it. A product with variants or modifiers opens a sheet first: pick the size (or other option), the modifiers, and the quantity, and the Add button shows the line\'s price as you go. A required modifier must be picked before the item can be added. The grid shows your first 500 active products by name; typing in the search box finds a product by the start of a word in its name across the whole catalog.\n- Quick keys — the ★ Quick keys chip, first in the category bar, shows only the products you marked Quick key at the register in the product editor: your best sellers, one tap away. Each register device reopens on the chip it was left on. Typing in the search box searches the whole catalog, not just the quick keys.\n- Categories — the chips after All show one category each.\n- Changing a line — tap a line in the basket to change its variant, modifiers or quantity (type a number or use + and −), or remove it. The + and − beside each line change the quantity by one. Two of the same item with the same choices are one line; the same item with a different choice is a line of its own.\n- Barcode scanners — any keyboard-wedge scanner works: it types the code into the search box and presses Enter, which adds the exact SKU/barcode match, variant included. A product with modifiers opens its sheet with that variant already picked. No drivers or pairing needed.\n- Charge — when the basket is ready, tap Charge. That prices the sale (tax is added at this step) and opens it'
3639
+ },
3640
+ {
3641
+ path: '/commerce-and-bookings/commerce/pos-and-reservations',
3642
+ title: 'POS & reservations',
3643
+ heading: 'Taking payment',
3644
+ anchor: '#taking-payment',
3645
+ text: 'A sale can take as many payments as it needs. The amount box above the payment buttons starts at the whole balance; to split the bill, type a smaller amount and pick a tender, and the rest stays open for the next one. Every payment is listed with its status (Waiting, Approved, Declined, Canceled). The sale is paid when the balance reaches zero, and only then is the stock taken and the order completed.\n| Tender | What happens |\n| Cash | Enter what the customer handed you, or tap Exact or a round-up amount. The register shows the change to give. Less than the amount due is taken toward the sale and the rest stays open. |\n| Card reader | Sends the amount to a card reader; the customer taps, inserts or swipes there. Shown only when card readers are available for your store and one is registered. With more than one reader, pick which one under the buttons. |\n| Type card | Staff type the card into Stripe\'s own card form (card not present, such as an order taken over the phone). The card never touches the register, and the payment goes through Stripe\'s normal online checks, 3-D Secure included. |\n| Card (QR) | Shows a QR code; the customer scans it and pays on their phone, and the payment appears on the register as soon as it goes through. |\n| Gift card | Type or scan the code. Check balance shows what the card can spend; Apply card takes the smaller of that balance and what is due, so a card worth less than the sale leaves the rest open. |\n| Room | Charges a checked-in stay\'s folio. Shown only when a guest is checked in. |\nCard payments that are still waiting can be canceled, which frees that amount for another tender. If the card reader declines a card, Retry sends the same charge back to the reader, so the customer can try again or use another card.\nVoid sale cancels the wh'
3646
+ },
3647
+ {
3648
+ path: '/commerce-and-bookings/commerce/pos-and-reservations',
3649
+ title: 'POS & reservations',
3650
+ heading: 'Tips',
3651
+ anchor: '#tips',
3652
+ text: 'Tips are off until you turn them on. The settings are on your site\'s Admin → Plugins → Commerce page, in the Commerce settings card:\n- Ask for tips at the register — off by default.\n- Tip choices (%) — up to four percentages, separated by commas. Defaults to 15, 18, 20, 25.\nWith tips on, the payment panel shows a button for each percentage and No tip, so the cashier can choose one for the customer. With a customer display paired, Ask on display lets the customer pick a percentage, type an amount or choose no tip on their own screen. When no tip has been added yet, the card reader asks the customer itself, showing the first three of your percentages.\nA tip is added on top of the payment it rides on and can be at most that payment\'s amount. Tips are yours: they are not counted as sales and carry no platform fee.'
3653
+ },
3654
+ {
3655
+ path: '/commerce-and-bookings/commerce/pos-and-reservations',
3656
+ title: 'POS & reservations',
3657
+ heading: 'Receipts',
3658
+ anchor: '#receipts',
3659
+ text: 'When a sale is paid, the register shows the change due (for cash) and the receipt options. Receipts at the register, in the same Commerce settings card, decides what happens first:\n| Setting | What happens when the sale is paid |\n| Ask the customer (default) | With a customer display paired, the customer chooses email, text, print or no receipt on their screen. Without one, the cashier offers it. |\n| Always print | The receipt prints straight away. |\n| No receipt unless asked | Nothing is sent or printed unless the cashier does it. |\nWhatever the setting, the cashier can always type an address into Email receipt to and tap Send, type a phone number into Text receipt to and tap Text, or tap Print receipt (or Gift receipt, which leaves the prices off). Text receipts are shown only when text messages are available for your store. Receipts print on the 80 mm layout described in Printed receipts, through the browser\'s print dialog, so any receipt printer with a system print driver works; see POS hardware. Tap New sale to start the next one.'
3660
+ },
3661
+ {
3662
+ path: '/commerce-and-bookings/commerce/pos-and-reservations',
3663
+ title: 'POS & reservations',
3664
+ heading: 'Card readers',
3665
+ anchor: '#card-readers',
3666
+ text: 'A card reader takes card payments at the counter: the customer taps, inserts or swipes, and the reader can ask for a tip. The register works with Stripe\'s smart readers, the Stripe Reader S700 (and S710) and the BBPOS WisePOS E. Card readers are shown only when they are available for your store; when they are not, the POS devices card has no card reader controls and the register has no Card reader button.\nTo add a reader:\n1. On the reader, open Settings and choose Generate pairing code.\n2. In the console, open Commerce → Settings → POS devices and choose Add card reader.\n3. Enter the registration code the reader shows, give the reader a name (such as "Front counter reader") and, optionally, pick the register it belongs to. A reader left on Any register can be used from every register.\n4. The first reader you add asks for the store\'s address — where the reader is used. Stripe sets the reader up for that country.\nEach reader is listed with its register and an Online or Offline status, and can be renamed, moved to another register, or removed. A removed reader has to be registered again with a new code to be used. A reader must be switched on and connected to the internet to take a payment; the register warns you when the selected reader looks offline. See POS hardware for setup notes.\nTrying it in test mode In test mode, add a reader with the code simulated-wpe to get Stripe\'s simulated reader. While a payment waits on it, the register shows Simulate tap to complete it with a test card.'
3667
+ },
3668
+ {
3669
+ path: '/commerce-and-bookings/commerce/pos-and-reservations',
3670
+ title: 'POS & reservations',
3671
+ heading: 'Customer display',
3672
+ anchor: '#customer-display',
3673
+ text: 'A customer display is a tablet facing your customer. It shows your store\'s logo (or name) and a welcome line between sales, the basket with its total as you ring it up, and it lets the customer choose a tip and a receipt themselves.\nTo pair one:\n1. On the register, tap Pair display next to the Register heading. It shows an address and a 6-digit code. The code works once and expires in 10 minutes.\n2. On the tablet, open that address — your console address followed by /kiosk/commerce/pos-display — and enter the code. No one signs in on the tablet.\nOnce paired, the register\'s button reads Display connected. During a sale the display shows:\n- The basket — each line, the subtotal, any discount, the total and what has been paid so far. Once a tip is added it is shown on its own line, with the Total with tip under it. Amounts are in your store\'s currency.\n- Tip choices — when tips are on and the cashier taps Ask on display: a button per percentage, an amount the customer types, or no tip.\n- "Tap, insert or swipe your card on the reader." while a card reader payment waits.\n- Receipt choice — when Receipts at the register is Ask the customer: email, text (shown only when text messages are available for your store), print or no receipt. When the customer asks for an email receipt and Offer email sign-up on the customer display is on (it is by default), an unticked Email me news and offers box is shown under the address. Only a ticked box adds them to your marketing audience.\nAfter the customer answers, the display thanks them and says the cashier will finish up. When the sale is paid and the receipt is handled, it shows Thank you! for a few seconds and then returns to the welcome screen. The email address or phone number the customer typed is not kept on the display: it is cleare'
3352
3674
  },
3353
3675
  {
3354
3676
  path: '/commerce-and-bookings/commerce/pos-and-reservations',
@@ -3362,21 +3684,224 @@ export const DOCS_SECTION_INDEX = [
3362
3684
  title: 'POS & reservations',
3363
3685
  heading: 'Related',
3364
3686
  anchor: '#related',
3365
- text: '- Commerce overview\n- Product catalog'
3687
+ text: '- POS hardware\n- Commerce overview\n- Product catalog'
3688
+ },
3689
+ {
3690
+ path: '/commerce-and-bookings/commerce/pos-hardware',
3691
+ title: 'POS hardware',
3692
+ heading: '',
3693
+ anchor: '',
3694
+ text: 'POS hardware\nThe register runs in a browser, so it works on an iPad, an Android tablet, a laptop or a desktop at the counter. This page covers the hardware around it: a card reader, a customer display, a receipt printer, a kitchen printer, the cash drawer, barcode scanners and a label printer.\nPlan availability POS hardware comes with POS, on Pro and above. There is no extra charge for printers, scanners or customer displays.'
3695
+ },
3696
+ {
3697
+ path: '/commerce-and-bookings/commerce/pos-hardware',
3698
+ title: 'POS hardware',
3699
+ heading: 'Recommended kit',
3700
+ anchor: '#recommended-kit',
3701
+ text: '| Device | Recommended | Why |\n| Register | iPad (10th gen or newer) or an Android tablet on a stand | Touch-first, and the camera scans barcodes |\n| Receipt printer | Star mC-Print3 or Star TSP143IV (CloudPRNT), or Epson TM-m30III (Server Direct Print) | Prints from any device over the internet: no driver, no pairing, no app |\n| Cash drawer | Any 24 V drawer with an RJ12 cable, such as the Star CD3-1616 or the APG Vasario | Plugs into the printer\'s drawer port and opens when the printer tells it to |\n| Barcode scanner | Any USB or Bluetooth scanner in keyboard mode, or the tablet\'s camera | A scanner types the code like a keyboard, so it needs no setup |\n| Label printer | Rollo, Zebra ZD421/ZD621 or GK420d, DYMO LabelWriter 4XL or 5XL, Brother QL-1100 | Prints product labels and 4x6 shipping labels on thermal stock |'
3702
+ },
3703
+ {
3704
+ path: '/commerce-and-bookings/commerce/pos-hardware',
3705
+ title: 'POS hardware',
3706
+ heading: 'Card readers',
3707
+ anchor: '#card-readers',
3708
+ text: 'The register takes card-present payments on Stripe\'s smart readers:\n| Reader | Notes |\n| Stripe Reader S700 / S710 | Android-based smart reader for the countertop or the hand. |\n| BBPOS WisePOS E | Countertop smart reader. |\nBoth are sold by Stripe. They are smart readers: each one talks to Stripe over its own internet connection, so it does not need to be plugged into or paired by Bluetooth with the device the register runs on. Card readers are shown in the console only when they are available for your store.\nGetting a reader\nReaders take payments through Aglyn\'s Stripe account, which pays your store out, so a reader is registered to your store in Aglyn rather than in a Stripe Dashboard of your own. Any supported reader can be added with the pairing code it shows, including one that was registered somewhere else before: generating a new pairing code on the reader and adding it here moves it to your store.\nStripe sells its readers through the Terminal hardware shop in the Stripe Dashboard. If you buy one there with a Stripe account of your own, add it here with a fresh pairing code from the reader, as above. Use the pairing code rather than the reader\'s serial number or order number: those two only register a reader to the Stripe account that ordered it.\nSetting one up\n1. Charge the reader and switch it on. Stripe recommends leaving it plugged in and on, even when not in use, so it receives software updates.\n2. Connect it to the internet: Wi-Fi from the reader\'s Settings, or Ethernet through Stripe\'s optional dock or hub. Stripe\'s setup guides for the S700/S710 and the WisePOS E show where each setting is, including the admin passcode the reader\'s Settings asks for.\n3. On the reader, open Settings and generate a pairing code.\n4. In the console, add the reader under Comm'
3709
+ },
3710
+ {
3711
+ path: '/commerce-and-bookings/commerce/pos-hardware',
3712
+ title: 'POS hardware',
3713
+ heading: 'Receipt printers',
3714
+ anchor: '#receipt-printers',
3715
+ text: 'A cloud receipt printer collects its work from Aglyn over the internet, so a receipt prints from the register on any device, even one with no printer driver, and even when the printer is on a different network. Each printer belongs to one register.\nStar printers use CloudPRNT and Epson printers use Server Direct Print. Both come built into the models above.\nAdd a printer\n1. Go to Commerce → Settings. Each register has a Hardware card.\n2. Select Add printer on the register\'s card and choose the brand.\n3. Enter the model, a name such as Counter printer, and the printer\'s identity:\n- Star: the printer\'s MAC address. Hold the FEED button while you switch the printer on to print a self-test; the MAC address is on it. Use the Ethernet MAC even when the printer is on Wi-Fi.\n- Epson: any ID you choose, such as counter-1. You enter the same ID in the printer in step 5.\n4. Choose the paper width, whether the printer prints a receipt for every sale, whether it prints kitchen tickets, and whether a cash drawer is plugged into it. Select Add printer. The card shows the printer\'s URL. Copy it.\n5. Enter the URL in the printer\'s own settings page (open the printer\'s IP address, from the self-test, in a browser on the same network):\n- Star: sign in (user root; the password is public or the one on the printer\'s label), go to Settings → CloudPRNT, turn CloudPRNT on, paste the URL as the Server URL, set the polling interval to 5 seconds, then Submit and Save → Restart device.\n- Epson: in EPSON TMNet WebConfig, open Server Direct Print (under Web Service Settings on most models). Select Enable, enter the ID from step 3, paste the URL as the Server 1 URL, set the interval to 5 seconds, select Submit, and reset the printer.\n6. Within a minute the printer shows Online on the card. Select Test '
3716
+ },
3717
+ {
3718
+ path: '/commerce-and-bookings/commerce/pos-hardware',
3719
+ title: 'POS hardware',
3720
+ heading: 'Cash drawer',
3721
+ anchor: '#cash-drawer',
3722
+ text: 'Plug the drawer\'s RJ12 cable into the DK (drawer kick) port on the back of the printer, and turn on A cash drawer is plugged into this printer in the printer\'s settings. The drawer then opens:\n- on every sale paid in cash, including a sale paid partly in cash and partly by card, as the receipt starts printing (or on its own when that printer does not print receipts),\n- when the shift records cash paid in, paid out or dropped to the safe, and when a return is refunded in cash,\n- from Open drawer on the Hardware card.\nA drawer only opens within two minutes of the sale that asked for it. If the printer was offline for longer, the drawer stays shut rather than springing open later at an unattended counter.'
3723
+ },
3724
+ {
3725
+ path: '/commerce-and-bookings/commerce/pos-hardware',
3726
+ title: 'POS hardware',
3727
+ heading: 'Barcode scanning',
3728
+ anchor: '#barcode-scanning',
3729
+ text: '- USB or Bluetooth scanners work with no setup: the scanner types the code and presses Enter, and the register adds the product whose barcode or SKU matches. It works whether or not the search box has focus, so you can scan straight after tapping a product or a button. A scan made while a payment window is open is ignored. Set the scanner to send Enter after each code; most do out of the box.\n- The camera works on a tablet or phone: select the scan button beside the register\'s search box, or beside a variant\'s Barcode field in the product editor, and hold the barcode inside the frame. The camera reads EAN-13, UPC-A, EAN-8 and Code128 everywhere. Chrome on Android and on a Mac also reads UPC-E, Code 39 and QR codes. The first time, allow the browser to use the camera.\nFor a busy counter, a handheld scanner is faster than the camera.'
3730
+ },
3731
+ {
3732
+ path: '/commerce-and-bookings/commerce/pos-hardware',
3733
+ title: 'POS hardware',
3734
+ heading: 'Label printers',
3735
+ anchor: '#label-printers',
3736
+ text: 'Product labels\nPrint price and barcode labels for your shelves and stock:\n1. Go to Commerce → Catalog and select Labels on a physical product.\n2. Choose the label size, 2.25 x 1.25 in or 2 x 1 in, and how many copies of each variant to print. Each label carries the product name, the variant\'s options, its price, and a barcode of the variant\'s barcode, or of its SKU when it has no barcode. A variant with neither cannot print a label; add one in the product editor first.\n3. Select Print, choose the label printer and the same label size in the print dialog, and print at 100% scale. Or select Download ZPL and send the file to a Zebra printer (with Zebra Setup Utilities, for example), which prints it without a print dialog.\nA valid EAN-13, UPC-A or EAN-8 prints as that symbology; any other code prints as Code 128. Every label scans back at the register, with a handheld scanner or the camera.\nShipping labels\nShipping labels bought through Pirate Ship or ShipStation come as 4x6 inch PDFs, which any thermal label printer prints from the browser:\n1. Install the printer\'s driver (Rollo, Zebra, DYMO and Brother all provide one for Mac and Windows) and load 4x6 labels.\n2. Open the label PDF and print it. In the print dialog choose the label printer, the 4x6 (or 100 x 150 mm) paper size, and Actual size or 100% scale, never Fit to page.\n3. Print one label to check the barcode is sharp and nothing is cut off. The browser remembers these settings for the next label.'
3737
+ },
3738
+ {
3739
+ path: '/commerce-and-bookings/commerce/pos-hardware',
3740
+ title: 'POS hardware',
3741
+ heading: 'Customer display tablet',
3742
+ anchor: '#customer-display-tablet',
3743
+ text: 'Any tablet with a modern browser can be the customer display. It needs an internet connection, but not a sign-in: you pair it with a code from the register, as described in Customer display.\nFor a counter that runs all day:\n- Put the tablet on a stand facing the customer; landscape gives the basket and the tip buttons the most room.\n- Keep it plugged in, and set the tablet not to sleep or lock while the display page is open.\n- Use the tablet\'s own single-app or guided-access mode, if it has one, so customers cannot leave the display page.\n- Add the display page to the home screen or bookmark it, so it can be reopened quickly after a restart. A paired display stays paired until you sign it out under Commerce → Settings → POS devices, remove its register, or clear the tablet browser\'s data for the console.'
3744
+ },
3745
+ {
3746
+ path: '/commerce-and-bookings/commerce/pos-hardware',
3747
+ title: 'POS hardware',
3748
+ heading: 'Related',
3749
+ anchor: '#related',
3750
+ text: '- POS & reservations\n- Running the register\n- Product catalog'
3751
+ },
3752
+ {
3753
+ path: '/commerce-and-bookings/commerce/pos-operations',
3754
+ title: 'Running the register',
3755
+ heading: '',
3756
+ anchor: '',
3757
+ text: 'Running the register\nEverything a till needs between the first sale of the day and the last: a counted cash drawer, a quick way to change who is ringing, the customer in front of you, returns, and a proper printed receipt. All of it runs from the register at /{site}/pos. Staff PINs are set under Commerce → Settings, and the register\'s rules under the site\'s Admin → Plugins → Commerce.\nPlan availability These are part of the point of sale, so they need Pro or above, like the register itself. Only members who can use the register — a site admin or editor whose Manage POS permission is on — can open shifts, switch in, look customers up or take returns.'
3758
+ },
3759
+ {
3760
+ path: '/commerce-and-bookings/commerce/pos-operations',
3761
+ title: 'Running the register',
3762
+ heading: 'Shifts and the cash drawer',
3763
+ anchor: '#shifts-and-the-cash-drawer',
3764
+ text: 'A shift is one stretch of trading on one register, counted against one cash drawer.\n1. Open a shift from the strip above the basket and enter the starting cash (the float) you counted into the drawer.\n2. While it is open, every sale on that register is counted in the shift. Use Cash in/out to record cash that moves without a sale:\n- Paid in — cash added to the drawer, such as change from the bank.\n- Paid out — cash taken for an expense, with a reason.\n- Safe drop — cash moved from the drawer to the safe.\n3. X report shows the shift so far at any time and changes nothing.\n4. Close shift, count the drawer and enter what is in it. The Z report freezes the shift\'s figures, and the register is free for the next shift.\nA register has one open shift at a time. If two tablets try to open the same register at once, one opens it and the other is told a shift is already open.\nWhat the reports show\nSales (orders, gross sales, discounts, tax, tips, refunds and net sales), the same broken down by tender (cash, card, gift card and room charge), and the drawer:\n| | |\n| Starting cash | the float you counted when the shift opened |\n| + Cash sales | what cash sales took (change handed back is not counted), plus cash tips |\n| + Paid in | |\n| − Paid out | |\n| − Safe drops | |\n| − Cash refunds | returns paid out of the drawer during the shift |\n| = Expected in drawer | |\nThe variance is what you counted minus what was expected: positive means the drawer is over, negative means it is short. Print either report on your receipt printer from its dialog.\nShift history\nCommerce → Orders → Shift history lists each register\'s shifts, newest first, with net sales, expected and counted cash and the variance. Click a closed shift for its Z report, and use Export CSV for a spreadsheet of the shifts list'
3765
+ },
3766
+ {
3767
+ path: '/commerce-and-bookings/commerce/pos-operations',
3768
+ title: 'Running the register',
3769
+ heading: 'Staff PINs',
3770
+ anchor: '#staff-pins',
3771
+ text: 'A shared tablet stays signed in; each person switches in with their own PIN instead of signing out.\n- Set your 4–6 digit PIN under Commerce → Settings → Staff PINs. A PIN that is one digit repeated or a straight run like 1234 is refused.\n- At the register, tap Switch cashier, pick your name and enter your PIN. Every sale, shift and return you ring is recorded under you until someone else switches in.\n- A PIN never grants more than your role: the register checks your role and your Manage POS permission each time it is used, so removing someone\'s access takes effect on their next tap.\n- Five wrong PINs in a row lock that person out for 15 minutes. A workspace admin can reset or remove anyone\'s PIN, which also lifts a lockout.\n- Lock the register after (minutes idle) in Admin → Plugins → Commerce locks the register after that long without a tap, so the next person has to enter their PIN. Tap Lock to lock it yourself.\nPINs are stored only as salted hashes and nobody can read them back, not even a workspace admin.'
3772
+ },
3773
+ {
3774
+ path: '/commerce-and-bookings/commerce/pos-operations',
3775
+ title: 'Running the register',
3776
+ heading: 'Customers at the register',
3777
+ anchor: '#customers-at-the-register',
3778
+ text: 'Search the Customer field by name, email or phone to attach a customer to the sale. The register shows how many orders they have placed at your store and what they have spent. The order is saved under their email and their name, so it appears on their record, prints their name on the receipt and can have its receipt emailed.\nNew customer adds someone in a few taps (an email is required, a phone is optional). Adding a customer does not sign them up for marketing email.\nThe search reads the people your workspace keeps in the CRM. Without it you can still type an email for the receipt.'
3779
+ },
3780
+ {
3781
+ path: '/commerce-and-bookings/commerce/pos-operations',
3782
+ title: 'Running the register',
3783
+ heading: 'Returns and exchanges',
3784
+ anchor: '#returns-and-exchanges',
3785
+ text: 'Tap Return on the register, then type the order number, scan the barcode at the foot of the receipt, or enter the customer\'s email.\n1. Pick the items coming back, how many of each, and the reason.\n2. Leave Put the items back in stock on to restock them at the register\'s location.\n3. Refund. The money goes back to how the customer paid:\n- Card — refunded through Stripe to the same card.\n- Cash — paid out of the drawer; the register tells you how much to hand over, and the open shift counts it.\n- Gift card — added back to the same gift card. A voided or frozen gift card cannot take a refund.\n- Room charge — taken back off the stay\'s folio.\nA sale paid more than one way is refunded to cards first, then gift cards and room charges, and to cash last. Turn on Split by hand to choose the amounts yourself; a payment can never take back more than it paid.\nEach unit\'s refund is its price less its share of any discount, plus its share of the tax, so returning items one at a time refunds exactly what returning them together would.\nEvery register return is also listed under Returns, beside the returns customers ask for online, already marked refunded. Items a customer has already asked to return online are held for that return: the register shows them as In an online return and will not refund them a second time.\nExchanges: after the return, tap Ring up the exchange to start a new sale for the same customer.\nRefund limits and manager approval\nCashier refund limit ($) in Admin → Plugins → Commerce is the largest return a cashier may refund without a manager. It is $0 by default, so every register refund needs a manager until you raise it. Above the limit the register asks a workspace admin to enter their PIN to approve that one refund. Workspace admins have no limit.'
3786
+ },
3787
+ {
3788
+ path: '/commerce-and-bookings/commerce/pos-operations',
3789
+ title: 'Running the register',
3790
+ heading: 'Printed receipts',
3791
+ anchor: '#printed-receipts',
3792
+ text: 'Receipts print on any 80 mm receipt printer through your browser\'s print dialog. Each receipt has your logo and store name, the order number and its barcode, the date, cashier and register, the customer\'s name, every item, discounts, tax, the total, how it was paid (card with its last four digits), the tip and change, and your receipt footer from Commerce → Settings. Two more lines are set in Admin → Plugins → Commerce: Address on printed receipts, printed under your store name, and Return policy on printed receipts, printed at the foot.\n- After each sale, the register shows Print receipt and Gift receipt for that sale until the next one completes.\n- Gift receipt prints the items and the barcode without any prices.\n- Reprint any register sale from its order on the Orders page: open the order and use Print receipt or Gift receipt.\nMost network receipt printers open the cash drawer cabled to them whenever they print, so printing a cash sale\'s receipt also opens the drawer. That is a setting on the printer.'
3793
+ },
3794
+ {
3795
+ path: '/commerce-and-bookings/commerce/pos-operations',
3796
+ title: 'Running the register',
3797
+ heading: 'Related',
3798
+ anchor: '#related',
3799
+ text: '- POS & reservations\n- Commerce overview'
3800
+ },
3801
+ {
3802
+ path: '/commerce-and-bookings/commerce/sales-channels',
3803
+ title: 'Sales channels',
3804
+ heading: '',
3805
+ anchor: '',
3806
+ text: 'Sales channels\nSales channels put your catalog in front of shoppers on Google (Shopping, free listings, Search, Images and YouTube), Meta (Facebook and Instagram), TikTok, Pinterest, Snapchat and Microsoft Shopping (Bing and Copilot). Each channel reads its own product feed from your store on a schedule you set on the channel\'s side, so a price, photo or stock change reaches it without another upload.\nSales channels come with every plan that sells online. They are set up under Products → Settings → Sales channels, with one card per channel.'
3807
+ },
3808
+ {
3809
+ path: '/commerce-and-bookings/commerce/sales-channels',
3810
+ title: 'Sales channels',
3811
+ heading: 'Turn on a channel',
3812
+ anchor: '#turn-on-a-channel',
3813
+ text: '1. On the channel\'s card, switch the feed On. The card shows the feed\'s address.\n2. Select Copy address.\n3. Follow the steps on the card: each one opens the channel\'s own setup and says where the address goes. In short:\n| Channel | Where the address goes | Format |\n| -- | -- | -- |\n| Google | Merchant Center → Products → add products from a file → enter a link to your file | XML |\n| Meta | Commerce Manager → Catalog → Data sources → data feed → scheduled feed | XML |\n| TikTok | Ads Manager → Assets → Catalogs → add products with a data feed → scheduled feed | CSV |\n| Pinterest | Ads → Catalogs → create a data source | TSV |\n| Snapchat | Ads Manager → Catalogs → add products from a feed URL | CSV |\n| Microsoft | Microsoft Advertising → Merchant Center → Catalog → Feeds → scheduled download | Text |\nSet the channel to fetch at least daily. Products appear on YouTube through Google: link your YouTube channel to Merchant Center in Merchant Center\'s settings.\nThe address appears once the site has a web address — a subdomain or a custom domain — and it is always on your store\'s own domain.\nKeep the address private {#keep-the-address-private}\nEach feed\'s address carries a long random code, different for every channel, and the feed answers only that address. Anyone holding it can read what your storefront already shows publicly, nothing more. If an address is shared by mistake, select Replace address (site admins): the old address stops at once and the card shows the new one to paste into the channel.\nSwitching a feed Off stops it answering; switching it back on keeps the same address, so the channel picks up where it left off.'
3814
+ },
3815
+ {
3816
+ path: '/commerce-and-bookings/commerce/sales-channels',
3817
+ title: 'Sales channels',
3818
+ heading: 'What each product sends',
3819
+ anchor: '#what-each-product-sends',
3820
+ text: 'Every active product is listed; drafts, archived and deleted products never are. A product with options (sizes, colors) is listed once per variant, grouped so the channel shows them as one product with choices.\nEach listing carries:\n- the name (with the variant\'s choices), description, product page link and photos — the variant\'s own photo first, then up to 10 more (20 for Meta);\n- the price in your store\'s currency, and the sale price when a compare-at price is set above it;\n- availability from your stock: in stock, out of stock, or backorder when the product keeps selling after it runs out;\n- the brand, barcode (GTIN), part number (MPN), condition and Google product category — see below;\n- your store\'s category path, and the variant\'s color and size;\n- the weight and, for Google, the packed size;\n- shipping: the cheapest rate to each country your shipping zones name, from the same rates checkout charges.\nThere is no limit on catalog size.\nBrand, barcode and category {#brand-barcode-and-category}\nChannels match listings to products they know by their identifiers. In the product editor, the Shopping channels section holds a product\'s:\n- Brand — what shoppers know it by.\n- Barcode (GTIN) — the UPC, EAN, ISBN or JAN on the packaging. A product with variants keeps a barcode per variant, in each variant\'s barcode field. A barcode whose last (check) digit does not match is not sent, because channels refuse it.\n- Part number (MPN) — the manufacturer\'s number, for products with no barcode.\n- Condition — new, refurbished or used.\n- Google product category — an id such as 2271 or a path such as Apparel & Accessories > Clothing > Dresses.\nA product you make yourself usually has no barcode: leave it blank, and the feed tells Google and Microsoft the product has no manufacturer ide'
3821
+ },
3822
+ {
3823
+ path: '/commerce-and-bookings/commerce/sales-channels',
3824
+ title: 'Sales channels',
3825
+ heading: 'Check your products',
3826
+ anchor: '#check-your-products',
3827
+ text: 'Select Check products on the Sales channels card. Each channel\'s card then counts the products it lists, leaves out and lists with suggestions, and Show products names each one with what to fix.\nA product is left out of a channel\'s feed when the channel would refuse it anyway:\n- it has no photo or no price;\n- it is a service, or sold only as a subscription — shopping channels list goods sold at one price;\n- the site has no web address yet, or no product page template is chosen in the store settings, so the product\'s link would not open.\nA suggestion means the product is listed but may show less widely: no barcode or part number, no description (its name is sent instead), a name longer than the channel shows, clothing without a Color and a Size option, or missing shipping.'
3828
+ },
3829
+ {
3830
+ path: '/commerce-and-bookings/commerce/sales-channels',
3831
+ title: 'Sales channels',
3832
+ heading: 'How fresh the feed is',
3833
+ anchor: '#how-fresh-the-feed-is',
3834
+ text: 'A product you edit and save reaches the next fetch at once. Stock that a sale takes reaches it within 30 minutes. Each card shows when the channel last read its feed.'
3835
+ },
3836
+ {
3837
+ path: '/commerce-and-bookings/commerce/sales-channels',
3838
+ title: 'Sales channels',
3839
+ heading: 'The earlier Google Merchant Center address',
3840
+ anchor: '#earlier-merchant-center-address',
3841
+ text: 'Stores that set up Merchant Center before sales channels existed used an address ending in /api/commerce/feed?hostId=…. It keeps working, now with everything above, until you retire it: once Merchant Center reads the Google card\'s address, select Turn off beside the earlier address on the Google card. Replacing the Google address turns it off too.'
3842
+ },
3843
+ {
3844
+ path: '/commerce-and-bookings/commerce/sales-channels',
3845
+ title: 'Sales channels',
3846
+ heading: 'Turn sales channels off for a site',
3847
+ anchor: '#turn-off',
3848
+ text: 'Sales channels are on for every site in a workspace. A site admin can switch them off for one site under Admin → Plugins → Sales channels. Every feed of that site, the earlier Google address included, then stops answering; each feed\'s address, switch and the defaults are kept for when it is switched back on.'
3849
+ },
3850
+ {
3851
+ path: '/commerce-and-bookings/commerce/sales-channels',
3852
+ title: 'Sales channels',
3853
+ heading: 'Related',
3854
+ anchor: '#related',
3855
+ text: '- Catalog\n- Shipping'
3856
+ },
3857
+ {
3858
+ path: '/commerce-and-bookings/commerce/shipping',
3859
+ title: 'Shipping',
3860
+ heading: '',
3861
+ anchor: '',
3862
+ text: 'Shipping\nShipping is set up under Products → Settings → Shipping. Every order that ships is priced from the zones and rates you save there, at the storefront\'s cart, on a product\'s Buy button, and on a draft order\'s payment link.'
3863
+ },
3864
+ {
3865
+ path: '/commerce-and-bookings/commerce/shipping',
3866
+ title: 'Shipping',
3867
+ heading: 'Zones and rates',
3868
+ anchor: '#zones-and-rates',
3869
+ text: 'A zone owns countries; is the rest of the world. A rate belongs to one zone and prices a parcel in one of four ways:\n| Rate type | What the shopper pays |\n| -- | -- |\n| Flat | One price. |\n| Free over subtotal | One price, or nothing once the cart reaches the subtotal you set. |\n| Subtotal tiers | The price of the first tier the cart\'s subtotal fits under. |\n| Weight tiers | The price of the first tier the cart\'s weight fits under. Weight is each variant\'s weight times its quantity. |\nLocal pickup adds a free collection choice beside your rates. It does not widen where you ship: a destination no rate reaches is still refused.\nCheckout charges only the rates of the zone the destination falls in, and narrows the address it collects to that destination, so a shopper cannot pick another zone\'s cheaper rate. The destination coverage rules explain what your zones make checkout ask and refuse.'
3870
+ },
3871
+ {
3872
+ path: '/commerce-and-bookings/commerce/shipping',
3873
+ title: 'Shipping',
3874
+ heading: 'Where parcels ship from',
3875
+ anchor: '#where-parcels-ship-from',
3876
+ text: 'Each inventory location (Products → Settings → Inventory locations) can carry a postal address: choose Add address on its row, or Edit address once it has one. The address is the street, an optional apartment or suite, city, state or region, postal code, the two-letter country code and a phone number, saved beside the location\'s name.'
3877
+ },
3878
+ {
3879
+ path: '/commerce-and-bookings/commerce/shipping',
3880
+ title: 'Shipping',
3881
+ heading: 'Carrier accounts',
3882
+ anchor: '#carrier-accounts',
3883
+ text: 'The Carrier accounts card lists the carriers your labels and checkout rates come from, for every site in the workspace. By default these are Aglyn\'s own accounts, marked Discounted rates. A switch on each row turns that carrier on or off.\nIf you have your own negotiated carrier account, choose Connect your own account and pick the carrier. Which carriers are listed depends on the shipping provider behind your labels. For UPS and FedEx you enter the account number, a contact and the account\'s address, and UPS then asks you to sign in at UPS; a row that still needs it shows Sign-in needed or Reconnect needed. Other carriers, such as DHL Express or Canada Post, ask for the credentials that carrier issued you, which are passed to the provider to connect the account and not kept by Aglyn. Labels bought on your own account are billed to you by the carrier, so Aglyn charges nothing for them.'
3884
+ },
3885
+ {
3886
+ path: '/commerce-and-bookings/commerce/shipping',
3887
+ title: 'Shipping',
3888
+ heading: 'Shipping labels',
3889
+ anchor: '#shipping-labels',
3890
+ text: 'A label bought on Aglyn\'s carrier accounts is charged to the workspace at the carrier\'s price, with nothing added. It is taken from your Stripe balance when the label is bought, once a member has agreed to that; when Stripe cannot take it, the label goes on the workspace\'s monthly invoice instead. A voided label that the carrier refunds is given back the same way it was paid.\nBilling → Usage shows a Shipping labels card once the workspace has bought a label: for each month, how many labels, how much came from the Stripe balance, how much went on the invoice, and what voided labels returned.'
3366
3891
  },
3367
3892
  {
3368
3893
  path: '/commerce-and-bookings/commerce/store-import-and-export',
3369
3894
  title: 'Import and export store data',
3370
3895
  heading: '',
3371
3896
  anchor: '',
3372
- text: 'Import and export store data\nYour store\'s products, categories, orders, discounts, coupons and gift cards each have an Export button, and the ones a file may change have an Import button. Export lets you pick every field, including computed ones. Import shows you how each column is read and which record each row matches, and asks how to handle every conflict before anything is written.\n| What | Where | Import | Export |\n| Products and variants | Products page, above the table | Yes | Yes |\n| Categories | Categories & collections card | Yes | Yes |\n| Discounts | Discounts card | Yes | Yes |\n| Coupons | Coupons card | Yes | Yes |\n| Orders | Orders tab, Export orders | No | Yes |\n| Gift cards | Gift cards card | Yes, by issuing each card | Yes |\nYou need permission to manage the site\'s data to import or undo an import. Importing gift cards also needs you to be an owner or admin of the workspace, or an admin of the site. Exporting needs read access to the site.'
3897
+ text: 'Import and export store data\nYour store\'s products, categories, orders, discounts, coupons and gift cards each have an Export button, and the ones a file may change have an Import button. Export lets you pick every field, including computed ones. Import shows you how each column is read and which record each row matches, and asks how to handle every conflict before anything is written.\n| What | Where | Import | Export |\n| Products and variants | Products page, above the table | Yes | Yes |\n| Categories | Categories & collections card | Yes | Yes |\n| Discounts | Discounts card | Yes | Yes |\n| Coupons | Coupons card | Yes | Yes |\n| Orders | Orders tab, Export orders or Export for shipping | No | Yes |\n| Gift cards | Gift cards card | Yes, by issuing each card | Yes |\n| Tracking numbers | Orders tab, Import tracking | Yes, by shipping each order | Yes |\nYou need permission to manage the site\'s data to import or undo an import. Importing gift cards also needs you to be an owner or admin of the workspace, or an admin of the site. Exporting needs read access to the site.'
3373
3898
  },
3374
3899
  {
3375
3900
  path: '/commerce-and-bookings/commerce/store-import-and-export',
3376
3901
  title: 'Import and export store data',
3377
3902
  heading: 'Export',
3378
3903
  anchor: '#export',
3379
- text: 'Export opens a dialog with every field the records have, grouped and searchable:\n- Presets fill the field list. Re-importable (the default) puts the Aglyn ID and the fields a re-import matches on first, then every field an import can write, so the file comes back in and finds its records. Everything adds computed and system fields. Minimal keeps the ID and the match fields. You can save your own list as a preset, and your last choice is remembered.\n- Records: everything, or what the list\'s filters and search find. On the Products page and the Orders tab, the filter is the same query the table runs, so the file holds every match in the store, not only the page on screen. There is no 5,000-order limit.\n- Format: CSV for a spreadsheet (with an optional byte-order mark for Excel), JSON, or NDJSON.\nThe file is built on the server and checked when it arrives. A download that stops short is refused rather than saved half-written.\nProducts are a row per variant\nA product with three variants is three rows. The product\'s own fields (title, description, tags and so on) are on its first row, and every row carries the product\'s Handle and its ID. Images follow the same pattern: the first image on the first row, the next on the second, and extra rows holding only the handle and an image when a product has more images than variants.\nThe Shopify preset\nProducts have a Shopify preset. It writes Shopify\'s product CSV: Shopify\'s columns, in Shopify\'s order, under Shopify\'s column names (Handle, Title, Body (HTML), Option1 Name, Variant SKU, Variant Price, Image Src and the rest), so the file can be uploaded to Shopify as it is. It leaves out Status, because Published says the same thing, and Kind, which Shopify\'s Type column does not mean.'
3904
+ text: 'Export opens a dialog with every field the records have, grouped and searchable:\n- Presets fill the field list. Re-importable (the default) puts the Aglyn ID and the fields a re-import matches on first, then every field an import can write, so the file comes back in and finds its records. Everything adds computed and system fields. Minimal keeps the ID and the match fields. You can save your own list as a preset, and your last choice is remembered.\n- Records: everything, or what the list\'s filters and search find. On the Products page and the Orders tab, the filter is the same query the table runs, so the file holds every match in the store, not only the page on screen. There is no 5,000-order limit.\n- Format: CSV for a spreadsheet (with an optional byte-order mark for Excel), JSON, or NDJSON.\nThe file is built on the server and checked when it arrives. A download that stops short is refused rather than saved half-written.\nProducts are a row per variant\nA product with three variants is three rows. The product\'s own fields (title, description, tags and so on) are on its first row, and every row carries the product\'s Handle and its ID. Images follow the same pattern: the first image on the first row, the next on the second, and extra rows holding only the handle and an image when a product has more images than variants.\nThe Shopify preset\nProducts have a Shopify preset. It writes Shopify\'s product CSV: Shopify\'s columns, in Shopify\'s order, under Shopify\'s column names (Handle, Title, Body (HTML), Option1 Name, Variant SKU, Variant Price, Image Src and the rest), so the file can be uploaded to Shopify as it is. It leaves out Status, because Published says the same thing, and Kind, which Shopify\'s Type column does not mean.\nExport for shipping, in the Orders card\'s header,'
3380
3905
  },
3381
3906
  {
3382
3907
  path: '/commerce-and-bookings/commerce/store-import-and-export',
@@ -3385,6 +3910,146 @@ export const DOCS_SECTION_INDEX = [
3385
3910
  anchor: '#import',
3386
3911
  text: 'Import opens an eight-step wizard:\n1. Upload a CSV, JSON or NDJSON file. The separator, encoding and header row are detected, and you can change any of them.\n2. Columns: each column is matched to a field, with how sure the match is and why. A Shopify product export is recognized column for column. Remap or ignore any column.\n3. Values: list values the store does not hold. For a product\'s Kind, Status or When sold out, map each unknown value to one the store has, leave it blank, or refuse the rows. For Categories, you can also add a name as a new category.\n4. Matching: how many rows find an existing record, how many are new, and which are ambiguous.\n5. Conflicts: what happens on a match (update, skip or make a copy), on no match (create or skip), and per field (overwrite, fill only blank fields, keep what is there). Rules the store keeps are shown locked with the reason. A gift card import adds a Confirm the cards step here (see Gift cards).\n6. Review: a dry run of every row, with a before → after table and every class of warning. Each class needs an "I understand" before Import is enabled.\n7. Import writes in chunks. You can pause and resume it.\n8. Results: a result file of every row, and Undo for seven days. A record edited since the import is shown to you rather than overwritten.\nBy default an import fills blank fields and never overwrites what a record already has. To change prices, stock or anything else that is set, choose Overwrite for those fields in the Conflicts step.\nProducts\nRows that share a Handle are one product: the first row\'s product fields, every row\'s variant, every row\'s image. A row without a handle is a product of its own, and its handle is made from its title.\n- Matching tries the Handle, then the SKU, then the Aglyn ID. A matched product is updat'
3387
3912
  },
3913
+ {
3914
+ path: '/commerce-and-bookings/commerce/use-pirate-ship',
3915
+ title: 'Use Pirate Ship with Aglyn',
3916
+ heading: '',
3917
+ anchor: '',
3918
+ text: 'Use Pirate Ship with Aglyn\nPirate Ship has no connection other apps can call, so you move orders with two files: one out, one back. The same steps work for Shippo, EasyPost and any label tool that reads a spreadsheet.\n1. Export for shipping in Aglyn writes the orders you still have to ship.\n2. Upload it to Pirate Ship and buy the labels.\n3. Export Pirate Ship\'s shipments and Import tracking in Aglyn. Each order is marked shipped and your customer gets the shipped email with the tracking link.\nBoth buttons are in the header of the Orders card, on the Orders tab of your site\'s Products hub.'
3919
+ },
3920
+ {
3921
+ path: '/commerce-and-bookings/commerce/use-pirate-ship',
3922
+ title: 'Use Pirate Ship with Aglyn',
3923
+ heading: 'Export the orders to ship',
3924
+ anchor: '#export',
3925
+ text: '1. Select Export for shipping and choose Pirate Ship.\n2. The export dialog opens on the orders still to ship: paid and partly shipped orders that have something physical in them. Downloads, services and register sales aren\'t included.\n3. Select Export. The file has one row per order with the columns Pirate Ship expects: Order ID, Name, Email, Phone, Address 1, Address 2, City, State, Zip, Country, Ounces and Items.\nOunces is the weight of what is still to ship, from each product\'s variant weight. When no product in the order has a weight, the cell is blank and Pirate Ship uses the default package weight you enter when you upload. A partly shipped order lists only what is left.\nThe other presets lay out the same orders for other tools:\n| Preset | Columns |\n| Shippo | Shippo\'s order CSV: Order Number, Recipient Name, Street Line 1, City, State/Province, Zip/Postal Code, Country, Order Weight and Order Weight Unit (oz), and more. |\n| EasyPost | reference, toaddress. and parcel.weightoz. EasyPost also needs your from address, carrier and service in each row; add those columns before you upload. |\n| Shipping (any tool) | Every shipping column under its own name, with the weight in ounces and pounds. |\nYou can change the fields before you export, like any export.'
3926
+ },
3927
+ {
3928
+ path: '/commerce-and-bookings/commerce/use-pirate-ship',
3929
+ title: 'Use Pirate Ship with Aglyn',
3930
+ heading: 'Buy the labels in Pirate Ship',
3931
+ anchor: '#labels',
3932
+ text: '1. In Pirate Ship, choose Ship → Upload a Spreadsheet and drop in the file.\n2. The first time, Pirate Ship asks what each column holds. Map Ounces to the weight override. Pirate Ship remembers the mapping for next time.\n3. Buy the labels.'
3933
+ },
3934
+ {
3935
+ path: '/commerce-and-bookings/commerce/use-pirate-ship',
3936
+ title: 'Use Pirate Ship with Aglyn',
3937
+ heading: 'Import the tracking numbers',
3938
+ anchor: '#import',
3939
+ text: '1. In Pirate Ship, open your shipments (a blank search on the Ship page), make sure the Order ID, Tracking Number and Carrier columns are showing, and select Export.\n2. In Aglyn, select Import tracking on the Orders card and upload the file.\n3. Aglyn matches the columns: order number, tracking number, carrier, and optionally a tracking link, a SKU and a quantity. Check the matching and continue.\n4. Each row is matched to its order by the order number. Review what will happen, then Apply.\nWhat each row does:\n- The order still has items to ship: the row records a shipment with the tracking number and ships everything left on the order. Your customer gets the shipped email. To split an order across parcels, give each row the SKU and Quantity in that parcel.\n- The tracking number is already on the order: nothing changes. Importing the same file twice is safe.\n- The order has already shipped with a different tracking number: that\'s a conflict, and you decide on the Conflicts step. Keep existing (the default) leaves the order as it is. Overwrite for Tracking number replaces the tracking on its latest shipment.\n- No order with that number, or a canceled, refunded or unpaid order: the row fails and the results say why. A tracking file never creates an order.\nYou need to be an admin or editor of the site to import tracking numbers. Undo on the import\'s results takes back what it recorded: each shipment it made is canceled, and each tracking number it replaced is put back.'
3940
+ },
3941
+ {
3942
+ path: '/commerce-and-bookings/commerce/use-pirate-ship',
3943
+ title: 'Use Pirate Ship with Aglyn',
3944
+ heading: 'Related',
3945
+ anchor: '#related',
3946
+ text: '- Use ShipStation with Aglyn\n- Use ShippingEasy with Aglyn\n- Import and export store data\n- Commerce'
3947
+ },
3948
+ {
3949
+ path: '/commerce-and-bookings/commerce/use-shippingeasy',
3950
+ title: 'Use ShippingEasy with Aglyn',
3951
+ heading: '',
3952
+ anchor: '',
3953
+ text: 'Use ShippingEasy with Aglyn\nIf you buy labels in ShippingEasy, connect it to your Aglyn store. Each order is sent to your ShippingEasy account as soon as it is paid. When you buy a label there, ShippingEasy tells Aglyn: the order is marked shipped with its tracking number, and your customer gets the shipped email with the tracking link.\nYou need to be an admin of the site to connect ShippingEasy, because the connection sends every order\'s name and address to your ShippingEasy account. You use your own ShippingEasy account and its API keys. There is nothing to sign up for in Aglyn.'
3954
+ },
3955
+ {
3956
+ path: '/commerce-and-bookings/commerce/use-shippingeasy',
3957
+ title: 'Use ShippingEasy with Aglyn',
3958
+ heading: 'Before you start',
3959
+ anchor: '#before-you-start',
3960
+ text: 'In ShippingEasy:\n1. Add a store of the API type, if you don\'t have one yet. Aglyn sends orders into this store.\n2. Note three values:\n- the API key and API secret, under Settings → API Credentials;\n- the store API key of your API store, under Settings → Stores & Orders.'
3961
+ },
3962
+ {
3963
+ path: '/commerce-and-bookings/commerce/use-shippingeasy',
3964
+ title: 'Use ShippingEasy with Aglyn',
3965
+ heading: 'Connect ShippingEasy',
3966
+ anchor: '#connect',
3967
+ text: '1. In Aglyn, open your site\'s Products hub, choose the Settings tab and find the ShippingEasy card.\n2. Select Connect ShippingEasy and paste the API key, API secret and store API key. Aglyn checks them with ShippingEasy before it saves them, and keeps the secret encrypted. Nobody can see the secret in Aglyn again, including you.\n3. The card shows a Callback URL. Copy it and paste it into your API store\'s settings in ShippingEasy, so each label you buy there comes back to Aglyn.\n4. Select Send open orders to send the orders that were paid before you connected.'
3968
+ },
3969
+ {
3970
+ path: '/commerce-and-bookings/commerce/use-shippingeasy',
3971
+ title: 'Use ShippingEasy with Aglyn',
3972
+ heading: 'What Aglyn sends',
3973
+ anchor: '#what-is-sent',
3974
+ text: '- Paid orders are sent when they are paid, as Awaiting Shipment, with the ship-to and billing address, the customer\'s email and phone, each item\'s SKU, quantity, price, weight and options, and the order\'s shipping, tax and discount.\n- Partly shipped orders list only what is still to ship.\n- An order you cancel or fully refund in Aglyn is canceled in ShippingEasy.\n- Test orders from Stripe\'s test mode aren\'t sent, because a label you buy in ShippingEasy is real postage.\n- Digital products, services and register sales handed over at the counter aren\'t sent, because there is nothing to ship. An order without a complete ship-to address (street, city, postal code and country) isn\'t sent either.\nWeights come from each product\'s variant weight in Aglyn. Each order is sent once: sending open orders again skips the ones already in ShippingEasy.'
3975
+ },
3976
+ {
3977
+ path: '/commerce-and-bookings/commerce/use-shippingeasy',
3978
+ title: 'Use ShippingEasy with Aglyn',
3979
+ heading: 'When you ship in ShippingEasy',
3980
+ anchor: '#ship',
3981
+ text: 'Buy the label as usual. When the label is ready, printed or the order is marked shipped, ShippingEasy sends Aglyn the tracking number, the carrier and the items. Aglyn:\n- records a shipment on the order for those items, with the tracking number and a tracking link for USPS, UPS, FedEx, DHL, Canada Post, Royal Mail and Australia Post;\n- marks the order Fulfilled, or Partially fulfilled when items are still to ship;\n- sends your customer the shipped email with the tracking link.\nThe same tracking number on the same order is recorded once. If ShippingEasy sends the shipment again, or you already typed that tracking number into the order in Aglyn, nothing changes. To avoid your customer getting two shipped emails, turn off ShippingEasy\'s own customer notification for this store.\nA label you void in ShippingEasy isn\'t recorded.'
3982
+ },
3983
+ {
3984
+ path: '/commerce-and-bookings/commerce/use-shippingeasy',
3985
+ title: 'Use ShippingEasy with Aglyn',
3986
+ heading: 'Change keys or disconnect',
3987
+ anchor: '#manage',
3988
+ text: '- Change keys replaces the API key, secret and store API key, for example after you make a new secret in ShippingEasy.\n- Send open orders sends the open orders from the last 90 days that aren\'t in ShippingEasy yet, up to 100 at a time.\n- Disconnect deletes the keys from Aglyn. New orders stop going to ShippingEasy and shipments it sends afterwards are refused. Orders already in ShippingEasy stay there, and orders already shipped stay shipped.\nThe card shows when an order was last sent and a shipment last received. When something goes wrong, the card says Needs attention and shows why, and the site\'s admins and editors get a notification if an order could not be sent after several tries.'
3989
+ },
3990
+ {
3991
+ path: '/commerce-and-bookings/commerce/use-shippingeasy',
3992
+ title: 'Use ShippingEasy with Aglyn',
3993
+ heading: 'Troubleshooting',
3994
+ anchor: '#troubleshooting',
3995
+ text: '| The card says | What to do |\n| ShippingEasy did not accept these keys | Copy all three again. The store API key belongs to an API store. |\n| ShippingEasy refused the API key, secret or store API key | The keys changed in ShippingEasy. Select Change keys and paste the new ones. |\n| Order n was refused by ShippingEasy | Fix what ShippingEasy names, usually the address, then select Send open orders. |\n| Order n could not be canceled in ShippingEasy | Cancel it in ShippingEasy yourself. |\n| Shipments never arrive | Check that the callback URL in your ShippingEasy API store is the one on the card. |'
3996
+ },
3997
+ {
3998
+ path: '/commerce-and-bookings/commerce/use-shippingeasy',
3999
+ title: 'Use ShippingEasy with Aglyn',
4000
+ heading: 'Related',
4001
+ anchor: '#related',
4002
+ text: '- Use ShipStation with Aglyn\n- Use Pirate Ship with Aglyn\n- Commerce'
4003
+ },
4004
+ {
4005
+ path: '/commerce-and-bookings/commerce/use-shipstation',
4006
+ title: 'Use ShipStation with Aglyn',
4007
+ heading: '',
4008
+ anchor: '',
4009
+ text: 'Use ShipStation with Aglyn\nIf you already buy labels in ShipStation, keep doing it. Connect your store to ShipStation as a Custom Store and ShipStation imports the orders you still have to ship. When you create a label, or mark an order shipped, ShipStation sends the shipment back to Aglyn: the order is marked shipped with its tracking number, and your customer gets the shipped email with the tracking link.\nYou need to be an admin of the site to connect ShipStation, because the connection can read every order\'s name and address. You don\'t need a ShipStation API key: ShipStation calls Aglyn, not the other way around.'
4010
+ },
4011
+ {
4012
+ path: '/commerce-and-bookings/commerce/use-shipstation',
4013
+ title: 'Use ShipStation with Aglyn',
4014
+ heading: 'Connect ShipStation',
4015
+ anchor: '#connect',
4016
+ text: '1. In Aglyn, open your site\'s Products hub, choose the Settings tab and find the ShipStation card.\n2. Select Connect ShipStation. The card shows the URL to custom XML page, a username and a password. Aglyn keeps the password encrypted, and a site admin can select Show on the card to see it again later.\n3. In ShipStation, go to Settings → Selling Channels → Store Setup, select Connect a Store or Marketplace and choose Custom Store.\n4. Paste the URL, username and password from Aglyn.\n5. Type the status names exactly as the Aglyn card shows them. ShipStation matches them letter for letter:\n| ShipStation field | Type |\n| Unpaid Status | unpaid |\n| Paid Status | paid |\n| Shipped Status | shipped |\n| Canceled Status | canceled |\n| On-Hold Status | onhold |\n6. Select Test Connection, then Connect.'
4017
+ },
4018
+ {
4019
+ path: '/commerce-and-bookings/commerce/use-shipstation',
4020
+ title: 'Use ShipStation with Aglyn',
4021
+ heading: 'What ShipStation imports',
4022
+ anchor: '#what-imports',
4023
+ text: 'ShipStation asks Aglyn for the orders that changed in a time window, and Aglyn answers with every order that has something to ship:\n- Paid orders arrive as Awaiting Shipment, with the ship-to address, the customer\'s email and phone, each item\'s SKU, quantity, price, weight, image and options, and the order\'s shipping, tax and discount.\n- Partly shipped orders list only what is still to ship, so a second parcel never asks for the whole order again.\n- An order you cancel or refund in Aglyn moves to ShipStation\'s canceled orders the next time it imports, and an order you ship from Aglyn moves to Shipped.\n- Digital products, services and register sales handed over at the counter aren\'t sent, because there is nothing to ship.\nWeights come from each product\'s variant weight in Aglyn. A product with no weight is sent without one, and ShipStation uses the package you choose there.\nAn order without a complete ship-to address (street, city, postal code and two-letter country) isn\'t sent, because ShipStation can\'t make a label for it and refuses the whole import if one order is incomplete.'
4024
+ },
4025
+ {
4026
+ path: '/commerce-and-bookings/commerce/use-shipstation',
4027
+ title: 'Use ShipStation with Aglyn',
4028
+ heading: 'When you ship in ShipStation',
4029
+ anchor: '#ship',
4030
+ text: 'Create the label as usual. ShipStation sends Aglyn the order number, the carrier, the service, the tracking number and the items in the parcel. Aglyn:\n- records a shipment on the order for those items, with the tracking number and a tracking link for USPS, UPS, FedEx, DHL, Canada Post, Royal Mail and Australia Post;\n- marks the order Fulfilled, or Partially fulfilled when items are still to ship;\n- sends your customer the shipped email with the tracking link.\nThe same tracking number on the same order is recorded once. If ShipStation sends the shipment again, or you already typed that tracking number into the order in Aglyn, nothing changes. To avoid your customer getting two shipped emails, turn off ShipStation\'s own customer notification for this store, or untick Notify customer there.'
4031
+ },
4032
+ {
4033
+ path: '/commerce-and-bookings/commerce/use-shipstation',
4034
+ title: 'Use ShipStation with Aglyn',
4035
+ heading: 'Make a new password or disconnect',
4036
+ anchor: '#manage',
4037
+ text: '- Show next to the password shows it again. Only a site admin can see it, and each time it\'s shown is recorded in the site\'s activity.\n- New password on the ShipStation card makes a new password and ends the old one at once. Paste the new password into ShipStation\'s store settings.\n- Disconnect stops ShipStation reading your orders. Shipments it sends afterwards are refused. Orders it already shipped stay shipped.\nThe card also shows when ShipStation last imported orders and last sent a shipment, so you can tell the connection is working.'
4038
+ },
4039
+ {
4040
+ path: '/commerce-and-bookings/commerce/use-shipstation',
4041
+ title: 'Use ShipStation with Aglyn',
4042
+ heading: 'Troubleshooting',
4043
+ anchor: '#troubleshooting',
4044
+ text: '| ShipStation says | What to do |\n| The username or password is wrong | Make a new password on the card and paste the new one into ShipStation. |\n| Commerce is switched off for this site | Turn the store back on for the site in Aglyn. |\n| This site\'s plan does not include selling | Selling needs a plan with commerce. |\n| No order n on this site | The order was deleted, or ShipStation is connected to a different site\'s URL. |\n| Too many requests | ShipStation retries on its own. |'
4045
+ },
4046
+ {
4047
+ path: '/commerce-and-bookings/commerce/use-shipstation',
4048
+ title: 'Use ShipStation with Aglyn',
4049
+ heading: 'Related',
4050
+ anchor: '#related',
4051
+ text: '- Use Pirate Ship with Aglyn\n- Use ShippingEasy with Aglyn\n- Import and export store data\n- Commerce'
4052
+ },
3388
4053
  {
3389
4054
  path: '/concepts/glossary',
3390
4055
  title: 'Glossary & naming conventions',
@@ -4671,7 +5336,7 @@ export const DOCS_SECTION_INDEX = [
4671
5336
  title: 'Share records across sites',
4672
5337
  heading: '',
4673
5338
  anchor: '',
4674
- text: 'Share records across sites\nEach site in your workspace sees the people it captured. A site in a consent group also sees the records of the group\'s other sites. Every other record is hidden from it, which is what keeps one agency client\'s CRM apart from another\'s.\nWhen you run several brands and want one brand\'s team to work records another brand captured, a workspace owner or admin can share them. You can share a lead, a contact, a company or a deal:\n- By hand: one record from its page, or a selection from the Leads or Contacts list.\n- By a sharing rule: every record the rule matches, including the ones you already have and every one captured or changed later.\nYou can share with chosen sites or with All sites. All sites includes sites you add to the workspace later.'
5339
+ text: 'Share records across sites\nEach site in your workspace sees the people it captured. A site in a consent group also sees the records of the group\'s other sites. Every other record is hidden from it, which is what keeps one agency client\'s CRM apart from another\'s.\nTo start every new record on All sites instead, a workspace owner or admin can change Default sharing for new records in the CRM\'s Settings. It covers new contacts, companies, deals and tasks, and changes nothing that already exists. It is separate from the defaults for new datasets and media files, which are set on the organization Data and Media pages.\nWhen you run several brands and want one brand\'s team to work records another brand captured, a workspace owner or admin can share them. You can share a lead, a contact, a company or a deal:\n- By hand: one record from its page, or a selection from the Leads or Contacts list.\n- By a sharing rule: every record the rule matches, including the ones you already have and every one captured or changed later.\nYou can share with chosen sites or with All sites. All sites includes sites you add to the workspace later.'
4675
5340
  },
4676
5341
  {
4677
5342
  path: '/content-and-data/crm/sharing',
@@ -4727,7 +5392,7 @@ export const DOCS_SECTION_INDEX = [
4727
5392
  title: 'Tasks & follow-ups',
4728
5393
  heading: '',
4729
5394
  anchor: '',
4730
- text: 'Tasks & follow-ups\nA task is a piece of work somebody on your team owes a person in the CRM: a call to return, an email to send, a meeting to hold, or a plain to-do. Every task has a subject, a type, a priority, a status, an optional due date and time, an optional assignee, notes, and a link to the contact, company or deal it is about.\nTasks live in the CRM hub at …/hosts/{site}/crm/tasks and, over every site at once, at …/{organization}/crm/tasks; every record page carries its own short list of them. They follow the same per-site visibility as the contacts themselves: a task made from one site\'s console is seen from that site (and the sites it shares an audience with), and an organization that has widened its default sharing sees every task everywhere. A task is also the one CRM record that can belong to no site at all — see Organization tasks.\nPlan availability Tasks are part of the CRM, included from Starter. On Free the section is shown locked, with the rest of the CRM. See What each plan includes.'
5395
+ text: 'Tasks & follow-ups\nA task is a piece of work somebody on your team owes a person in the CRM: a call to return, an email to send, a meeting to hold, or a plain to-do. Every task has a subject, a type, a priority, a status, an optional due date and time, an optional assignee, notes, and a link to the contact, company or deal it is about.\nTasks live in the CRM hub at …/hosts/{site}/crm/tasks and, over every site at once, at …/{organization}/crm/tasks; every record page carries its own short list of them. They follow the same per-site visibility as the contacts themselves: a task made from one site\'s console is seen from that site (and the sites it shares an audience with), and an organization that has set Default sharing for new records to All sites sees every task everywhere. A task is also the one CRM record that can belong to no site at all — see Organization tasks.\nPlan availability Tasks are part of the CRM, included from Starter. On Free the section is shown locked, with the rest of the CRM. See What each plan includes.'
4731
5396
  },
4732
5397
  {
4733
5398
  path: '/content-and-data/crm/tasks',
@@ -5000,7 +5665,7 @@ export const DOCS_SECTION_INDEX = [
5000
5665
  title: 'Datasets & Dynamic Content',
5001
5666
  heading: 'Who a dataset is shared with',
5002
5667
  anchor: '#who-a-dataset-is-shared-with',
5003
- text: 'Datasets belong to the workspace, not to a single site, so one dataset can drive pages on every site you run. When that isn\'t what you want, the Sharing control on each dataset decides which sites can see it:\n- All sites — everyone in the workspace, on every site.\n- Selected sites… — pick the sites that share it, up to 30.\nWhere a new dataset starts depends on where you create it and on your workspace\'s Default sharing for new data and media, the setting at the top of the workspace Media page:\n- Created on a site\'s Data page — it follows that setting. Set to All sites, the dataset starts on All sites. Set to Only the site they were created in, it starts shared with that site alone, and its control reads Selected sites… with just that site picked.\n- Created on the organization Data page — it starts on All sites whatever the setting says, because there is no site to limit it to.\n- Installed from the Marketplace, or created through the REST API — it starts on All sites too. Both act for the whole organization, not for one site.\nThe setting only decides where a new dataset starts. It changes nothing that already exists, and you can widen or narrow any dataset afterwards.\nA dataset with no sharing stored is visible to no site; its control reads Not shared with any site until you choose one of the two.\nThis matters most for agencies. If you run three internal sites alongside twelve client sites, your rate card can be shared with the internal three and stay invisible to the clients — including to the client collaborators you have invited, who will not see it in the Data page, the pickers, or anywhere else.\nSharing is enforced on the server, not just in the console. A site cannot render a dataset it hasn\'t been shared with even if a page explicitly asks for it by name.\nA few co'
5668
+ text: 'Datasets belong to the workspace, not to a single site, so one dataset can drive pages on every site you run. When that isn\'t what you want, the Sharing control on each dataset decides which sites can see it:\n- All sites — everyone in the workspace, on every site.\n- Selected sites… — pick the sites that share it, up to 30.\nWhere a new dataset starts depends on where you create it and on your workspace\'s Default sharing for new datasets, the setting at the top of the organization Data page (new media files have a default of their own, on the workspace Media page):\n- Created on a site\'s Data page — it follows that setting. Set to All sites, the dataset starts on All sites. Set to Only the site they were created in, it starts shared with that site alone, and its control reads Selected sites… with just that site picked.\n- Created on the organization Data page — it starts on All sites whatever the setting says, because there is no site to limit it to.\n- Installed from the Marketplace, or created through the REST API — it starts on All sites too. Both act for the whole organization, not for one site.\nThe setting only decides where a new dataset starts. It changes nothing that already exists, and you can widen or narrow any dataset afterwards.\nA dataset with no sharing stored is visible to no site; its control reads Not shared with any site until you choose one of the two.\nThis matters most for agencies. If you run three internal sites alongside twelve client sites, your rate card can be shared with the internal three and stay invisible to the clients — including to the client collaborators you have invited, who will not see it in the Data page, the pickers, or anywhere else.\nSharing is enforced on the server, not just in the console. A site cannot render a dataset it hasn\'t b'
5004
5669
  },
5005
5670
  {
5006
5671
  path: '/content-and-data/datasets/overview',
@@ -5203,7 +5868,7 @@ export const DOCS_SECTION_INDEX = [
5203
5868
  title: 'Media Library & CDN',
5204
5869
  heading: 'Upload',
5205
5870
  anchor: '#upload',
5206
- text: '- Upload images, PDFs, ZIP archives and documents (Word, Excel, PowerPoint, CSV, RTF, plain text, Markdown and JSON). Click Upload media, or drag files straight from your desktop onto the library — dropped files land in the folder you have open.\n- Video uploads are paused. New MP4, WebM and QuickTime files are not accepted on any plan for now, from the console or the API, and a video\'s file cannot be replaced. Videos already in your library keep playing, and the Video element can still use them. While the pause lasts, the library shows a Video uploads paused chip beside Upload media.\n- Documents and archives are stored and served exactly as you uploaded them — nothing is opened, extracted or converted. Macro-enabled Office files (.docm, .xlsm, .pptm) are not accepted.\n- Rename, replace the file behind an asset, and edit images in place. Replace works for images, PDFs, archives and documents alike, and for video once video uploads resume — it is available from the asset\'s details drawer and straight from the card\'s overflow menu, and it keeps the asset\'s link, folder, tags, alt text, custom fields and sharing exactly as they were. Swapping one kind of file for another is not allowed: upload that as a new file. Cropping, rotating and resizing stay images-only, for the obvious reason.\nSize and plan limits\n| Upload | Cap | Plan |\n| Images | 15 MB per file | Every plan |\n| PDFs | 25 MB per file | Pro and above |\n| Documents (Word, Excel, CSV, RTF, text, Markdown, JSON) | 25 MB per file | Pro and above |\n| Presentations (PowerPoint) | 50 MB per file | Pro and above |\n| ZIP archives | 50 MB per file | Pro and above |\n| Video | 200 MB per file | Paused on every plan |\nAny file over 3 MB automatically uses signed-URL uploads, so big files go straight to storage without tying up '
5871
+ text: '- Upload images, PDFs, ZIP archives and documents (Word, Excel, PowerPoint, CSV, RTF, plain text, Markdown and JSON). Click Upload media, or drag files straight from your desktop onto the library — dropped files land in the folder you have open.\n- Video uploads are paused. New MP4, WebM and QuickTime files are not accepted on any plan for now, from the console or the API, and a video\'s file cannot be replaced. Videos already in your library keep playing, and the Video element can still use them. While the pause lasts, the library shows a Video uploads paused chip beside Upload media.\n- Create images with AI. Create with AI, beside Upload media, draws an illustration, icon, pattern or logo mark as an SVG from a description, or makes a photo where photos are on, and adds it to the folder you have open with alt text. Each picture is stored like an upload and costs AI credits — see Create images with AI.\n- Web fonts (WOFF2) are accepted too. The usual way to add one is Upload your own font in the theme editor, which checks the font\'s license, converts a TTF, OTF or WOFF to WOFF2 and stores it here.\n- Documents and archives are stored and served exactly as you uploaded them — nothing is opened, extracted or converted. Macro-enabled Office files (.docm, .xlsm, .pptm) are not accepted.\n- Rename, replace the file behind an asset, and edit images in place. Replace works for images, PDFs, archives and documents alike, and for video once video uploads resume — it is available from the asset\'s details drawer and straight from the card\'s overflow menu, and it keeps the asset\'s link, folder, tags, alt text, custom fields and sharing exactly as they were. Swapping one kind of file for another is not allowed: upload that as a new file. Cropping, rotating and resizing stay images-only, '
5207
5872
  },
5208
5873
  {
5209
5874
  path: '/content-and-data/media/overview',
@@ -5217,7 +5882,7 @@ export const DOCS_SECTION_INDEX = [
5217
5882
  title: 'Media Library & CDN',
5218
5883
  heading: 'Who an asset is shared with',
5219
5884
  anchor: '#who-an-asset-is-shared-with',
5220
- text: 'Workspace media is shared across every site by default. The Shared with control narrows that, with the same two choices as datasets — All sites or Selected sites…. You\'ll find it in three places:\n- on a single asset, in its details drawer;\n- on a selection — tick several files and use Shared with… in the toolbar;\n- on a folder, from its ⋮ menu, which offers to apply the same sharing to the files inside it and its subfolders (it names the count, so you know what you\'re about to change).\nA folder applies its sharing when you save it — files keep their own setting afterwards, so moving a file into a "Client A" folder later does not re-share it. Narrowing a file that sites are already using names those sites first and asks you to confirm. Only workspace owners and admins can change sharing.\nA new folder or file starts shared with All sites, so it appears everywhere the moment you create it — or with the site you were working in, if your workspace has been set to make new resources site-scoped by default. That default is Default sharing for new data and media, at the top of the workspace\'s Media page, and it changes nothing that already exists. The site you were working in is the one whose Media tab you uploaded on, or the one you were editing when you opened the media picker. A folder or file created on the workspace Media page has no site to limit it to, so it starts on All sites either way. The default applies to new datasets the same way: one created on a site\'s Data page follows it, and one created on the organization Data page starts on All sites. If the Shared with dialog ever opens on "Not shared with any site", that folder or file has no sharing stored at all: it is hidden from every site, and any file inside it turns up under No folder there. Pick a value and save '
5885
+ text: 'Workspace media is shared across every site by default. The Shared with control narrows that, with the same two choices as datasets — All sites or Selected sites…. You\'ll find it in three places:\n- on a single asset, in its details drawer;\n- on a selection — tick several files and use Shared with… in the toolbar;\n- on a folder, from its ⋮ menu, which offers to apply the same sharing to the files inside it and its subfolders (it names the count, so you know what you\'re about to change).\nA folder applies its sharing when you save it — files keep their own setting afterwards, so moving a file into a "Client A" folder later does not re-share it. Narrowing a file that sites are already using names those sites first and asks you to confirm. Only workspace owners and admins can change sharing.\nA new folder or file starts shared with All sites, so it appears everywhere the moment you create it — or with the site you were working in, if your workspace has been set to make new media site-scoped by default. That default is Default sharing for new media, at the top of the workspace\'s Media page, and it changes nothing that already exists. The site you were working in is the one whose Media tab you uploaded on, or the one you were editing when you opened the media picker. A folder or file created on the workspace Media page has no site to limit it to, so it starts on All sites either way. New datasets have a default of their own, Default sharing for new datasets on the organization Data page, so files can start on every site while datasets start on one, or the other way round. If the Shared with dialog ever opens on "Not shared with any site", that folder or file has no sharing stored at all: it is hidden from every site, and any file inside it turns up under No folder there. Pick a'
5221
5886
  },
5222
5887
  {
5223
5888
  path: '/content-and-data/media/overview',
@@ -5931,21 +6596,21 @@ export const DOCS_SECTION_INDEX = [
5931
6596
  title: 'Injection zones',
5932
6597
  heading: '',
5933
6598
  anchor: '',
5934
- text: 'Injection zones\nRegister a widget with ConsoleExtension.widgets: [{ slot, widgetId, title?, Component }]; the shell renders it through PluginWidgetSlot. The guaranteed zones are the exported CONSOLEWIDGETSLOTS catalog — slot stays an open string so custom zones don\'t need a core release.\n| Zone | Where it renders | Props your widget receives |\n| hostActivity | Host dashboard + a page\'s detail view: the activity column | hostId, targetId?, header?, viewAllHref? |\n| hostDashboard | Host dashboard glance row, one card per capability | hostId |\n| orgDashboard | The organization\'s Sites page, above the site grid — the org-level twin of hostDashboard, rendered only for an org-wide member who may open the org-level CRM | hostId (always null), orgMount, basePath (the org-level hub\'s path) |\n| commerceGlance | Host dashboard commerce summary | hostId |\n| orgData | Organization → Data page body | orgId, org |\n| besignerFunctions | Besigner ƒx panel | hostId |\n| hostArtifactPublish | Wherever a console page offers to publish something it holds (a site\'s layouts, the organization\'s publish panel): the dialog that publishes it. The page keeps the control that opens it, and leaves that control out when no widget is registered here | artifact ({ kind, hostId?, orgId?, artifactId?, displayName?, description? }, or null while nothing is open), onClose() |\n| orgPluginInstalls | Organization → Plugins, above the built-in plugins: the plugins your plugin installed into the workspace, one row per installation, each linking to /[orgSlug]/plugins/[pluginRef] | orgId, orgSlug, hosts ({ id, label } for each site the reader can see) |\n| pluginInstallStatus | An installation\'s own page, above where it runs: what the installing plugin says about the version the workspace runs. Drawn only for an in'
6599
+ text: 'Injection zones\nRegister a widget with ConsoleExtension.widgets: [{ slot, widgetId, title?, Component }]; the shell renders it through PluginWidgetSlot. The guaranteed zones are the exported CONSOLEWIDGETSLOTS catalog — slot stays an open string so custom zones don\'t need a core release.\n| Zone | Where it renders | Props your widget receives |\n| hostActivity | Host dashboard + a page\'s detail view: the activity column | hostId, targetId?, header?, viewAllHref? |\n| hostDashboard | Host dashboard glance row, one card per capability | hostId |\n| orgDashboard | The organization\'s Sites page, above the site grid — the org-level twin of hostDashboard, rendered only for an org-wide member who may open the org-level CRM | hostId (always null), orgMount, basePath (the org-level hub\'s path) |\n| commerceGlance | Host dashboard commerce summary | hostId |\n| hostAnalytics | A site\'s Analytics page, below its traffic cards: a whole section a plugin computes, such as Funnels | hostId, orgId |\n| orgData | Organization → Data page body | orgId, org |\n| besignerFunctions | Besigner ƒx panel | hostId |\n| hostArtifactPublish | Wherever a console page offers to publish something it holds (a site\'s layouts, the organization\'s publish panel): the dialog that publishes it. The page keeps the control that opens it, and leaves that control out when no widget is registered here | artifact ({ kind, hostId?, orgId?, artifactId?, displayName?, description? }, or null while nothing is open), onClose() |\n| orgPluginInstalls | Organization → Plugins, above the built-in plugins: the plugins your plugin installed into the workspace, one row per installation, each linking to /[orgSlug]/plugins/[pluginRef] | orgId, orgSlug, hosts ({ id, label } for each site the reader can see) |\n| pluginInstallStatus | An'
5935
6600
  },
5936
6601
  {
5937
6602
  path: '/developers/plugins/reference/injection-zones',
5938
6603
  title: 'Injection zones',
5939
6604
  heading: 'Zones a plugin hosts',
5940
6605
  anchor: '#zones-a-plugin-hosts',
5941
- text: 'A zone can sit on a plugin\'s own surface rather than on a console page, such as hostForms on the forms plugin\'s Forms page, hostAutomations, automationEditor and automationRun on the workflows plugin\'s Automation page, or recordInsights, recordEmail and importMapping on the CRM plugin\'s record pages, one-to-one composer and import drawers, and in the import wizard. A plugin cannot import the console\'s PluginWidgetSlot, so the shell hands its renderer down: read it with useConsoleWidgetSlot() from @aglyn/aglyn and draw the zone through it.\nThe renderer is the same gated slot a console page mounts, so a widget there passes the same enablement, entitlement and permission gates. Outside the console shell it is null, and the zone draws nothing.\nA plugin that hosts a zone also declares it, with registerPluginZone and a token that carries the props it hands each widget (see Zones a plugin hosts in the plugin-manager reference). The forms, workflows and commerce plugins declare these on their own surfaces; a widget from another plugin restates the props it reads rather than importing the host\'s package:\n| Zone | Where it renders | Props your widget receives |\n| hostForms | A site\'s Forms page, the forms plugin\'s, beside Create Form: another way to start a form | hostId, orgId |\n| hostAutomations | The workflows plugin\'s Automation page, its Actions, beside Add action and Recipes: another way to start an automation | hostId, orgId, openAction(actionId) — opens a listed action in the Actions editor, and answers false for one the list has not read yet |\n| automationEditor | Inside the editor of one saved automation, an action or a workflow, on the Automation page | hostId, orgId, target ({ type: \'action\' \\| \'workflow\', id, name }, the automation as it is stored) |\n| automationRun '
6606
+ text: 'A zone can sit on a plugin\'s own surface rather than on a console page, such as hostForms on the forms plugin\'s Forms page, hostEmailTemplates on the email plugin\'s templates list, hostCampaigns on the marketing plugin\'s Campaigns, hostAutomations, automationEditor and automationRun on the workflows plugin\'s Automation page, orgAutomations on its Org automations section, hostLogic, logicFunctionEditor and logicReferenceIssue on the logic plugin\'s Functions & Variables page, or recordInsights, recordEmail and importMapping on the CRM plugin\'s record pages, one-to-one composer and import drawers, and in the import wizard. A plugin cannot import the console\'s PluginWidgetSlot, so the shell hands its renderer down: read it with useConsoleWidgetSlot() from @aglyn/aglyn and draw the zone through it.\nThe renderer is the same gated slot a console page mounts, so a widget there passes the same enablement, entitlement and permission gates. Outside the console shell it is null, and the zone draws nothing.\nA plugin that hosts a zone also declares it, with registerPluginZone and a token that carries the props it hands each widget (see Zones a plugin hosts in the plugin-manager reference). The forms, email, marketing, workflows and commerce plugins declare these on their own surfaces; a widget from another plugin restates the props it reads rather than importing the host\'s package:\n| Zone | Where it renders | Props your widget receives |\n| hostForms | A site\'s Forms page, the forms plugin\'s, beside Create Form: another way to start a form | hostId, orgId |\n| hostEmailTemplates | A site\'s email templates, the email plugin\'s, beside New template and in the empty list: another way to start an email design | hostId, orgId |\n| hostAutomations | The workflows plugin\'s Automation page: on A'
5942
6607
  },
5943
6608
  {
5944
6609
  path: '/developers/plugins/reference/injection-zones',
5945
6610
  title: 'Injection zones',
5946
6611
  heading: 'How a zone spaces your widget',
5947
6612
  anchor: '#how-a-zone-spaces-your-widget',
5948
- text: 'Most zones are a stack. The shell draws their widgets one under another, with the same gap the page puts between its own cards, and keeps that gap between the zone and the page\'s cards beside it. Render your card with no outer margin: the zone spaces it, and a margin on your widget\'s root is reset.\nThe other zones hand each widget to a layout the page draws itself, and the page spaces it there:\n- hostDashboard, commerceGlance and orgDashboard: a tile of a dashboard grid.\n- hostScreens, hostTemplates, hostLayouts, hostForms, hostComponents and besignerToolbar: a control in a row.\n- hostAutomations, automationEditor and automationRun: a control the workflows plugin places beside its Actions buttons, in an automation\'s editor, and on a failed run.\n- siteMember: a section of a site user\'s drawer.\n- besignerInspector and seoFields: a section among a panel\'s own fields.\n- besignerPageProperties: a section of the Page Properties drawer\'s column.\n- hostScreenRow: a chip in a Pages list row, beside the page\'s own chips.\n- productEditor, productsHub and productImport: a section the commerce plugin places among its product editor\'s fields, above its catalog table, and in its import wizard\'s After import step.\n- recordEmail and importMapping: a section the CRM plugin places under its one-to-one composer\'s message and under an import drawer\'s or the import wizard\'s column matching.\n- besignerFunctions, orgData, orgMarketplace, orgAddons and marketplaceListing: the body of a dialog or a page.\n- consoleDock: a floating dock.\n- consoleTopBar: a control in the top bar\'s row.\n- besignerInteractions: nothing; a widget there reports to the section and renders null.\n- orgMembersListColumn, staffOrgsListColumn and staffOrgUsageColumn: a column of a table, or, on staffOrgUsageColumn, a line a'
6613
+ text: 'Most zones are a stack. The shell draws their widgets one under another, with the same gap the page puts between its own cards, and keeps that gap between the zone and the page\'s cards beside it. Render your card with no outer margin: the zone spaces it, and a margin on your widget\'s root is reset.\nThe other zones hand each widget to a layout the page draws itself, and the page spaces it there:\n- hostDashboard, commerceGlance and orgDashboard: a tile of a dashboard grid.\n- hostScreens, hostTemplates, hostLayouts, hostForms, hostEmailTemplates, productsCreate, hostComponents, mediaLibrary and besignerToolbar: a control in a row.\n- hostAutomations, automationEditor and automationRun: a control the workflows plugin places beside its Actions buttons and in its Workflows card\'s header, in an automation\'s editor, and on a failed run.\n- orgAutomations: a control the workflows plugin places in its Org automations card\'s header.\n- hostLogic, logicFunctionEditor and logicReferenceIssue: a control the logic plugin places in its Functions and Variables cards\' headers, in a function\'s editor, and on a broken reference.\n- funnelsCreate and funnelInsight: a control the funnels plugin places beside New funnel and under a funnel\'s results.\n- siteMember: a section of a site user\'s drawer.\n- besignerInspector and seoFields: a section among a panel\'s own fields.\n- besignerPageProperties: a section of the Page Properties drawer\'s column.\n- hostScreenRow: a chip in a Pages list row, beside the page\'s own chips.\n- productEditor, productsHub and productImport: a section the commerce plugin places among its product editor\'s fields, above its catalog table, and in its import wizard\'s After import step.\n- orderDetail and orderFulfillment: a section the commerce plugin places in its order dialog, '
5949
6614
  },
5950
6615
  {
5951
6616
  path: '/developers/plugins/reference/injection-zones',
@@ -6078,7 +6743,7 @@ export const DOCS_SECTION_INDEX = [
6078
6743
  title: 'Plugin-manager API reference',
6079
6744
  heading: 'Console extensions — `feature-plugins`',
6080
6745
  anchor: '#console-extensions--feature-plugins',
6081
- text: '| API | What it does |\n| registerConsoleExtension(extension) | Declares everything a plugin adds to the console shell. Idempotent by pluginId (re-registration replaces). |\n| listConsoleNavItems() / resolveConsolePluginPage(href) | How the shell renders nav + serves plugin pages under /[orgSlug]/hosts/[host]/[...pluginSlug]. The resolver matches an exact href, or a declared section beneath one — longest href wins, prefixes match on a segment boundary, and a tie between two enabled plugins refuses. It answers { extension, navItem, section?, segments }. |\n| listConsoleOrgNavItems() / resolveConsoleOrgPluginPage(href) | The same pair for organization-level surfaces — the extension\'s orgNavItems, listed on the organization\'s tab strip and served under /[orgSlug]/[...pluginSlug] with the same matching rules. Neither pair reads the other\'s list. |\n| listConsoleWidgets(slot) | Widgets registered for a named zone — see Injection zones. |\n| listConsoleStaffPages() / resolveConsoleStaffPage(id) | How the shell draws a plugin\'s staff pages: a tab after the staff strip\'s own, and a page at /admin/{id} from the generic staff route. Two plugins claiming one id resolve to nothing, and say so. |\n| listConsoleProviders() | App-level providers mounted around every console page. |\n| defineUiFeatureBundle(options, components) | Site/canvas component bundle; auto-depends on the base mui bundle. Component and bundle ids are persisted in page docs — never rename. |\n| CONSOLEWIDGETSLOTS | The typed injection-zone catalog. A widget with a column: { header, sortKey?, align? } is a column of a shell-owned table on the zones documented as column zones. |\nConsoleExtension fields: pluginId, displayName, featureFlag? (plan-entitlement gate the shell applies — extensions cannot bypass plans), permissio'
6746
+ text: '| API | What it does |\n| registerConsoleExtension(extension) | Declares everything a plugin adds to the console shell. Idempotent by pluginId (re-registration replaces). |\n| listConsoleNavItems() / resolveConsolePluginPage(href) | How the shell renders nav + serves plugin pages under /[orgSlug]/hosts/[host]/[...pluginSlug]. The resolver matches an exact href, or a declared section beneath one — longest href wins, prefixes match on a segment boundary, and a tie between two enabled plugins refuses. It answers { extension, navItem, section?, segments }. |\n| listConsoleOrgNavItems() / resolveConsoleOrgPluginPage(href) | The same pair for organization-level surfaces — the extension\'s orgNavItems, listed on the organization\'s tab strip and served under /[orgSlug]/[...pluginSlug] with the same matching rules. Neither pair reads the other\'s list. |\n| listConsoleWidgets(slot) | Widgets registered for a named zone — see Injection zones. |\n| listConsoleStaffPages() / resolveConsoleStaffPage(id) | How the shell draws a plugin\'s staff pages: a tab after the staff strip\'s own, and a page at /admin/{id} from the generic staff route. Two plugins claiming one id resolve to nothing, and say so. |\n| listConsolePublicPages() / resolveConsolePublicPage(pluginId, path) | How the console serves a plugin\'s full-screen page that needs no staff session, at /kiosk/{pluginId}{path} — a screen facing customers, for example. The route loads only that plugin\'s console bundle, and only for a path its manifest lists in contributes.console.publicRoutes; the path matches exactly. First-party plugins only. |\n| listConsoleProviders() | App-level providers mounted around every console page. |\n| defineUiFeatureBundle(options, components) | Site/canvas component bundle; auto-depends on the base mui bundle. Co'
6082
6747
  },
6083
6748
  {
6084
6749
  path: '/developers/plugins/reference/plugin-manager-api',
@@ -6428,7 +7093,14 @@ export const DOCS_SECTION_INDEX = [
6428
7093
  title: 'Plugin-manager API reference',
6429
7094
  heading: 'Platform events — `plugin-events` (`/server`)',
6430
7095
  anchor: '#platform-events--plugin-events-server',
6431
- text: 'Core raises the events; a plugin that must react to what a core route did subscribes from its serverDeclarations entry, so the subscription is in place before the first request. Payloads carry the actor and the before / after, never a reference to the plugin.\n| Event | Raised by | Payload |\n| org.seatAddons.changed | the add-on checkout and the billing webhook | { orgId, actor, before, after } — the org.seatAddons maps |\n| org.permissions.changed | the member, role and host-member routes | { orgId, actor, subject: { type, id?, name? }, permission, granted } |\n| host.records.removed | the public API\'s deletes and a person\'s erasure, after the delete lands | { orgId, hostIds, collection, records: [{ id, data }] } — each removed document as it stood |\n| billing.invoice.paid | the billing webhook, once the invoice resolves to a workspace | { orgId, invoiceId, amountPaidCents, currency, paidOutOfBand, metadata } |\n| billing.invoice.failed | the billing webhook | { orgId, invoiceId, amountDueCents, metadata } |\n| billing.invoice.closed | the billing webhook, on voided and on markeduncollectible | { orgId, invoiceId, reason: \'voided\' \\| \'uncollectible\', metadata } |\n| billing.dispute.opened | the billing webhook, on a dispute that matched a workspace | { orgId, chargeId, invoiceId, amountCents } |\n| billing.paymentMethod.changed | the billing webhook, after reading the customer\'s default | { orgId, defaultType } |\nThe five billing events carry the Stripe object\'s own metadata, which core does not read. A plugin that stamped its own id on an invoice it created recognizes its own by it; every other handler ignores the event. They are awaited in the route rather than deferred, because a plugin\'s decision about whether a workspace may keep spending must not lag the payment that se'
7096
+ text: 'Core raises the events; a plugin that must react to what a core route did subscribes from its serverDeclarations entry, so the subscription is in place before the first request. Payloads carry the actor and the before / after, never a reference to the plugin.\n| Event | Raised by | Payload |\n| org.seatAddons.changed | the add-on checkout and the billing webhook | { orgId, actor, before, after } — the org.seatAddons maps |\n| org.permissions.changed | the member, role and host-member routes | { orgId, actor, subject: { type, id?, name? }, permission, granted } |\n| host.records.removed | the public API\'s deletes and a person\'s erasure, after the delete lands | { orgId, hostIds, collection, records: [{ id, data }] } — each removed document as it stood |\n| host.email.engaged | the email delivery webhook, for a message tagged with a site, after the delivery log records it | { hostId, events: [{ to, type, at, firstOfType }] } — opens and clicks only; firstOfType marks the first of its type for that message |\n| billing.invoice.paid | the billing webhook, once the invoice resolves to a workspace | { orgId, invoiceId, amountPaidCents, currency, paidOutOfBand, metadata } |\n| billing.invoice.failed | the billing webhook | { orgId, invoiceId, amountDueCents, metadata } |\n| billing.invoice.closed | the billing webhook, on voided and on markeduncollectible | { orgId, invoiceId, reason: \'voided\' \\| \'uncollectible\', metadata } |\n| billing.dispute.opened | the billing webhook, on a dispute that matched a workspace | { orgId, chargeId, invoiceId, amountCents } |\n| billing.paymentMethod.changed | the billing webhook, after reading the customer\'s default | { orgId, defaultType } |\nThe five billing events carry the Stripe object\'s own metadata, which core does not read. A plugin that stamped '
7097
+ },
7098
+ {
7099
+ path: '/developers/plugins/reference/plugin-manager-api',
7100
+ title: 'Plugin-manager API reference',
7101
+ heading: 'Plugin events — `plugin-domain-events` (`/server`)',
7102
+ anchor: '#plugin-events--plugin-domain-events-server',
7103
+ text: 'Events a plugin raises for other plugins, with payloads the raising plugin declares. A subscriber reaches an event by its name and never imports the plugin that raises it.\n| Call | What it does |\n| definePluginDomainEvent (name) | A typed token for one event name: dotted lower-case words, the first naming what it is about (order.paid). A subscriber in another plugin restates the payload type and defines its own token under the same name. |\n| declarePluginDomainEvents([{ event, label, description, payloadKeys? }], { pluginId? }) | Declares the events a plugin raises. One plugin owns a name; a second declaring it throws. |\n| subscribePluginDomainEvent(event, handler, { pluginId?, name? }) | Subscribes from serverDeclarations. name keeps two handlers of one plugin apart. The handler gets { id, event, hostId, orgId, occurredAtMs, attempt, payload }. |\n| listPluginDomainEvents() / listPluginDomainEventSubscribers(event) | What is declared and who listens, for pickers and diagnostics. |\nRaising goes through the outbox in the admin data lib (@aglyn/tenant-data-admin/server/plugin-event-outbox): stagePluginEvent inside the transaction that writes the fact, or raisePluginEvent after it. Both take a key naming the occurrence, so the same fact raised twice is one event. A core job delivers the outbox every minute.\nDelivery is at least once, per subscriber. A handler that throws is retried alone, with backoff from 30 seconds to 12 hours, eight times, and the event is then kept as a dead letter with each subscriber\'s last error. A subscriber that already took the event is not called again, but a handler can still see an event twice (it succeeded and the record of that did not land), so dedupe on the envelope\'s id. A locked site\'s events wait until the lock lifts.\nCommerce\'s order an'
6432
7104
  },
6433
7105
  {
6434
7106
  path: '/developers/plugins/reference/plugin-manager-api',
@@ -6731,6 +7403,13 @@ export const DOCS_SECTION_INDEX = [
6731
7403
  anchor: '#email',
6732
7404
  text: 'Where to get these: with the default provider, resend.com → API Keys, and Domains to verify the domain you send from. To send through anything else, see Which provider carries your mail.\nThe shared pool is yours to create, and nothing works until it exists\nA published site never sends from USAGEEMAILFROM. A site with a sending domain of its own sends as that; every other site sends its transactional mail — receipts, password resets, booking confirmations — from a member of a small shared pool inside your mail apex. Nothing provisions that pool for you.\nBefore any site sends, create AGLYNTENANTSHAREDPOOLSIZE domains at your mail provider — shared1.{mail apex} through shared{n}, four by default — publish the three records each one issues into your own zone, and verify all of them. Twelve records in total for the default pool, and that number does not grow with sites.\nSkip this and every site without a domain of its own refuses every message, receipts included, with tenant-identity-unprovisioned. Do not create a domain object for the bare mail apex: nothing sends from it, and the pool members are one label deeper so each one signs for itself.\nWhich provider carries your mail {#email-provider}\nEverything that decides whether a message may leave — suppressions, the send rate, the phishing screen, the sending identity, the unsubscribe footer — runs inside the product. The provider only carries the finished message, and you choose which one:\n| AGLYNMAILPROVIDER | What carries the mail |\n| resend | Resend, with RESENDAPIKEY. The only provider with a delivery feed, a credential probe and a read API, so it is the only one under which open and click statistics, automatic bounce and complaint suppression, the staff delivery history, the shared-pool health check and CRM email captur'
6733
7405
  },
7406
+ {
7407
+ path: '/developers/self-hosting-environment',
7408
+ title: 'Environment variables',
7409
+ heading: 'Mobile apps and push',
7410
+ anchor: '#mobile',
7411
+ text: 'The native apps (Aglyn and Aglyn POS, for iOS, iPadOS and macOS from apps/ios, and for Android and the Windows desktop from apps/android) are built, not served by your containers. Their settings are build settings, compiled into the app, so changing one means building and shipping the app again. None of them is a secret. On Apple they are xcconfig keys (copy apps/ios/Config/Production.xcconfig.example); on Android and the desktop they are Gradle settings, -Paglyn. =… or the AGLYN environment variable.\n| Apple (xcconfig) | Android (Gradle) | Need | Value |\n| AGLYNCONSOLEURL | consoleUrl | Required | Your console origin. Every API call and console page the app opens is on it, and it is the app\'s universal-link host. Default https://app.aglyn.com. |\n| AGLYNBRANDNAME | — | Optional | The app\'s name and the product name its copy says. Default Aglyn. |\n| AGLYNFIREBASEAPIKEY | firebaseApiKey | Required | The Firebase app config of the app you registered in your project, per bundle. |\n| AGLYNFIREBASEAUTHDOMAIN | firebaseAuthDomain | Required | As above. |\n| AGLYNFIREBASEPROJECTID | firebaseProjectId | Required | As above. |\n| AGLYNFIREBASEAPPID | firebaseAppId | Required | As above. |\n| AGLYNFIREBASEMESSAGINGSENDERID | firebaseMessagingSenderId | Optional | As above. |\n| AGLYNFIREBASESTORAGEBUCKET | — | Optional | As above. |\n| AGLYNGOOGLEIOSCLIENTID, AGLYNGOOGLEWEBCLIENTID | — | Optional | Google sign-in\'s OAuth client ids. The Google button is hidden until both are set. |\n| AGLYNAUTHEMULATORHOST | authEmulatorHost | Development | host:port of a local Auth emulator. Never set in a store build. |\n| AGLYNFIRESTOREEMULATORHOST | firestoreEmulatorHost | Development | host:port of a local Firestore emulator. Never set in a store build. |\nThe server side of push is configured in you'
7412
+ },
6734
7413
  {
6735
7414
  path: '/developers/self-hosting-environment',
6736
7415
  title: 'Environment variables',
@@ -7037,7 +7716,7 @@ export const DOCS_SECTION_INDEX = [
7037
7716
  title: 'Aglyn Assist',
7038
7717
  heading: 'Edits in the Besigner',
7039
7718
  anchor: '#edits-in-the-besigner',
7040
- text: 'With a page, a reusable component or a layout open in the Besigner, you can ask the assistant for a change: "make this hero darker", "add a testimonial band below", "point this button at the pricing page". When your plan includes AI generation — the Aglyn AI add-on, or the AI credits a Free workspace gets — it answers with a Proposed change card listing what would change: elements added, removed, moved or restyled, settings changed, and a page\'s search title or description filled in. Anything it could not match to your canvas is listed under Left out.\n- Nothing changes until you apply. Apply as draft puts the changes on the open canvas as unsaved edits, all in one step, so a single Undo takes the whole change back. Nothing is saved or published until you do that yourself. A proposed search title or description is filled into Page Properties, where Save SEO stores it.\n- The live version is never edited in place. When the version open is the one your live site shows, the card offers Make a new version instead — the same New version you would use yourself. Once the new version opens, the card offers Apply as draft there.\n- Select the element you mean. The assistant sees the element you have selected, everything inside it, what surrounds it and the page\'s sections — not your whole site — and it can only change elements it was shown. With nothing selected it sees only the top of the page and asks you to select one. If the canvas changes before you apply, the card says so and applies nothing.\n- Who can use it. Your role needs the Generate with AI permission (a site collaborator needs it on that site). Asking uses AI credits like any other assistant message; applying uses none. Each applied change is recorded in the site\'s activity log under your name.'
7719
+ text: 'With a page, a reusable component or a layout open in the Besigner, you can ask the assistant for a change: "make this hero darker", "add a testimonial band below", "point this button at the pricing page". When your plan includes AI generation — the Aglyn AI add-on, or the AI credits a Free workspace gets — it answers with a Proposed change card listing what would change: elements added, removed, moved or restyled, settings changed, interactions added, and a page\'s search title or description filled in. Anything it could not match to your canvas is listed under Left out.\n- Interactions on the selected element. Ask "when this is clicked, show the panel below" and the assistant proposes an interaction on the element: something a visitor does to it — a click, a hover, scrolling it into view — and the steps that follow, chosen from the presentational ones every plan runs (show, hide or toggle an element, add or remove a class, scroll to or play an element, open or close a drawer or menu, go to a page, show a message). It is added beside anything the element already does, never in place of it; edit or remove it under Interactions like any other. Ask "what does this do?" and it explains the interactions the element carries.\n- Nothing changes until you apply. Apply as draft puts the changes on the open canvas as unsaved edits, all in one step, so a single Undo takes the whole change back. Nothing is saved or published until you do that yourself. A proposed search title or description is filled into Page Properties, where Save SEO stores it.\n- The live version is never edited in place. When the version open is the one your live site shows, the card offers Make a new version instead — the same New version you would use yourself. Once the new version opens, the card offers Apply '
7041
7720
  },
7042
7721
  {
7043
7722
  path: '/getting-started/aglyn-assist',
@@ -7198,7 +7877,7 @@ export const DOCS_SECTION_INDEX = [
7198
7877
  title: 'Create a site',
7199
7878
  heading: 'Create your first site',
7200
7879
  anchor: '#create-your-first-site',
7201
- text: '1. Sign in to the console.\n2. Open the site switcher in the app bar (top-left) and choose Create site.\n3. Give it a name. Aglyn generates a working subdomain immediately, so the site has a real address from the first moment — you can attach a custom domain later.\nWhen you can use Aglyn AI, the new site opens on Start your site, which asks how you want to start: Start from the starter site, or Start with AI, which plans your pages from a few questions — see Generate a website from a prompt. Choosing the starter site, skipping or closing the window all give the site the starter described below. Until you choose, the site\'s address shows a short coming soon page with its name, kept out of search results.\nEvery other new site starts with the starter straight away. The starter is a complete website, published and open to search engines from the first visit:\n- a Home page at the site root with the sections an ordinary business site has — a hero with your site\'s name, what you offer, an about section, a photo gallery, testimonials, frequently asked questions, a call to action and a working contact form. Each section says how to make it yours, and the photos are placeholders to swap for your own under Media;\n- a shared header and footer layout every page you add renders inside, with your site\'s name, search, a light/dark switch and a Contact button. It is the site\'s one shared layout on the Free plan;\n- a theme (colors and fonts) under Setup → Theme, and a title, description and sharing image under Setup → SEO.\nOpen the Home page from Pages to make it your own: once you publish your changes it is your home page like any other, and a starter applied later adds its pages beside it instead of replacing it. Or replace it: the first page you publish at the site root — one you build,'
7880
+ text: '1. Sign in to the console.\n2. Open the site switcher in the app bar (top-left) and choose Create site.\n3. Give it a name. Aglyn generates a working subdomain immediately, so the site has a real address from the first moment — you can attach a custom domain later.\nWhen you can use Aglyn AI, the new site opens on Start your site, which asks how you want to start: Start from the starter site, or Start with AI, which plans your pages from a few questions — see Generate a website from a prompt. Choosing the starter site, skipping or closing the window all give the site the starter described below. Choosing Start from the starter site publishes it at once, and the console says so: Your site is live, with the site\'s address, View your site and Edit your pages. Until you choose, the site\'s address shows a short coming soon page with its name, kept out of search results.\nEvery other new site starts with the starter straight away. The starter is a complete website, published and open to search engines from the first visit:\n- a Home page at the site root with the sections an ordinary business site has — a hero with your site\'s name, what you offer, an about section, a photo gallery, testimonials, frequently asked questions, a call to action and a working contact form. Each section says how to make it yours, and the photos are placeholders to swap for your own under Media;\n- a shared header and footer layout every page you add renders inside, with your site\'s name, search, a light/dark switch and a Contact button. It is the site\'s one shared layout on the Free plan;\n- a theme (colors and fonts) under Setup → Theme, and a title, description and sharing image under Setup → SEO.\nOpen the Home page from Pages to make it your own: once you publish your changes it is your home page like '
7202
7881
  },
7203
7882
  {
7204
7883
  path: '/getting-started/create-a-site',
@@ -7415,7 +8094,7 @@ export const DOCS_SECTION_INDEX = [
7415
8094
  title: 'Commerce end to end',
7416
8095
  heading: '4. What checkout does',
7417
8096
  anchor: '#4-what-checkout-does',
7418
- text: 'Both buy buttons and the cart\'s Checkout redirect to Stripe-hosted Checkout, then back to your site with a success/canceled marker:\nPaying without leaving your site\nThere is a second checkout that keeps the shopper on your own pages: instead of sending them to checkout.stripe.com, the card form opens in place, below the Buy or Checkout button, styled with your site\'s theme. Leaving the store mid-purchase is one of the most common places a cart gets abandoned, so this exists to remove that step.\nRolling out. In-page checkout is off by default and is switched on per workspace by Aglyn staff (release flag In-page checkout). Until it is on for your workspace, checkout behaves exactly as described above — the redirect is what your shoppers see.\nNothing else about a sale changes when it is on, and that is deliberate:\n- The price, tax, shipping and any coupon are computed by the same code. The in-page form is the same Stripe Checkout Session as the redirect, just drawn by us instead of by Stripe — so the two cannot quote different totals.\n- Your order is still created by Stripe\'s webhook, never by the browser. If a shopper pays and immediately closes the tab, the order, the stock decrement, the receipt and the gift-card or license-key steps all still happen. If they pay and then refresh the page, none of it happens twice.\n- A declined card stays on the form. The basket, address and payment method the shopper already entered are kept, with the decline shown beside them, so they can try another card without starting over. Cards that ask for a bank verification step (3-D Secure) show that challenge in place.\n- Abandoned in-page checkouts are still recoverable and still feed the abandoned-cart emails, the same as an abandoned redirect.\nA shopper who cancels the in-page form is ret'
8097
+ text: 'Both buy buttons and the cart\'s Checkout open the payment form in place, on your own site, below the button. After paying, the shopper lands back on the same page with a success marker.\nPaying without leaving your site\nThe shopper never leaves your store for checkout.stripe.com. Leaving the store mid-purchase is one of the most common places a cart gets abandoned, so the whole checkout happens on your pages:\n- Email for the receipt. If the shopper already typed it in the cart, it is shown rather than asked for again.\n- Shipping address and shipping method, only when the order ships. The methods listed are the rates your shipping settings give for that destination, and choosing one updates the total.\n- Card or other payment method, through Stripe\'s Payment Element.\n- A live total: subtotal, any discount, shipping and tax, recalculated as the address and shipping method change, so the amount on screen is the amount charged.\nThe form uses your site\'s theme: its primary color, background and text colors, corner radius and font carry into the payment fields.\nNothing about the sale itself differs from the Stripe-hosted page, and that is deliberate:\n- The price, tax, shipping and any coupon are computed by the same code. The in-page form is the same Stripe Checkout Session as the redirect, just drawn by us instead of by Stripe — so the two cannot quote different totals.\n- Your order is still created by Stripe\'s webhook, never by the browser. If a shopper pays and immediately closes the tab, the order, the stock decrement, the receipt and the gift-card or license-key steps all still happen. If they pay and then refresh the page, none of it happens twice.\n- A declined card stays on the form. The basket, address and payment method the shopper already entered are kept, with the de'
7419
8098
  },
7420
8099
  {
7421
8100
  path: '/guides/commerce-end-to-end',
@@ -7933,7 +8612,7 @@ export const DOCS_SECTION_INDEX = [
7933
8612
  title: 'Cookie consent',
7934
8613
  heading: 'What needs consent',
7935
8614
  anchor: '#what-needs-consent',
7936
- text: 'Consent-gated — held back unless the visitor\'s recorded state grants analytics:\n- Google Analytics (your configured measurement ID) and every event Aglyn sends to it — see Google Analytics events.\n- Google Tag Manager (your configured container ID). The container is gated the same way and never more loosely, so it cannot be used to install a tag that runs before consent.\n- Core Web Vitals reporting. Page-speed metrics reach your property only through the same tag, and are discarded rather than held if consent is refused while a page is open.\n- Cross-visit A/B test identity: without an analytics grant, experiment variant assignment is remembered only for the visit (sessionStorage) instead of across visits.\n- Remembering the campaign that last touched a visitor. Reading it on the page they are on needs no grant; keeping it across visits does. See The campaign a visitor came from.\n- A Wistia player loaded with the page — see Videos that load with the page.\n- Advertising storage (adstorage, aduserdata, adpersonalization), on sites that have turned the advertising question on. Where it starts depends on the visitor\'s region, and it is the same split analytics uses:\n- Prior-consent regions. The EU/EEA, the UK, and any visitor whose region cannot be determined see the banner first, and advertising storage is denied until they tick that specific box. Not objecting is never a yes here.\n- Everywhere else. Advertising runs from their first visit, alongside analytics, on the same implied basis — these visitors see no banner, and Your Privacy Choices is where they turn it off. That is the opt-out posture the Privacy Policy and the Cookie Policy both describe.\n- A visitor who declines, opts out, or arrives with a Global Privacy Control signal gets no advertising storage anywhere in t'
8615
+ text: 'Consent-gated — held back unless the visitor\'s recorded state grants analytics:\n- Google Analytics (your configured measurement ID) and every event Aglyn sends to it — see Google Analytics events.\n- Google Tag Manager (your configured container ID). The container is gated the same way and never more loosely, so it cannot be used to install a tag that runs before consent.\n- Core Web Vitals reporting. Page-speed metrics reach your property only through the same tag, and are discarded rather than held if consent is refused while a page is open.\n- Cross-visit A/B test identity: without an analytics grant, experiment variant assignment is remembered only for the visit (sessionStorage) instead of across visits.\n- Funnel visits. On a site with a funnel, each visit\'s steps are tied together by a random id kept in that browser tab\'s session storage, and the id is sent with each step. No step is recorded until the visitor\'s state grants analytics; a refusal deletes the id. See What counts as a visit.\n- Remembering the campaign that last touched a visitor. Reading it on the page they are on needs no grant; keeping it across visits does. See The campaign a visitor came from.\n- A Wistia player loaded with the page — see Videos that load with the page.\n- Advertising storage (adstorage, aduserdata, adpersonalization), on sites that have turned the advertising question on. Where it starts depends on the visitor\'s region, and it is the same split analytics uses:\n- Prior-consent regions. The EU/EEA, the UK, and any visitor whose region cannot be determined see the banner first, and advertising storage is denied until they tick that specific box. Not objecting is never a yes here.\n- Everywhere else. Advertising runs from their first visit, alongside analytics, on the same implied basis — '
7937
8616
  },
7938
8617
  {
7939
8618
  path: '/marketing-and-automation/analytics/cookie-consent',
@@ -7984,6 +8663,62 @@ export const DOCS_SECTION_INDEX = [
7984
8663
  anchor: '#turn-the-banner-off',
7985
8664
  text: 'The switch at the top of the Cookie consent card turns the whole tool off. That means Google Analytics loads for every visitor without being asked — do this only if you run your own consent solution, and remember you remain responsible for the consent your visitors\' jurisdictions require.'
7986
8665
  },
8666
+ {
8667
+ path: '/marketing-and-automation/analytics/funnels',
8668
+ title: 'Funnels',
8669
+ heading: '',
8670
+ anchor: '',
8671
+ text: 'Funnels\nA funnel is an ordered list of two to eight steps you expect a visitor to take on your site — say, viewed a pricing page → viewed the sign-up page → submitted the sign-up form. Aglyn counts how many visitors reached each step in that order, how many dropped off between steps, and how long the steps took.\nFunnels are on your site\'s Analytics page, below the traffic cards.\nPlan availability Funnels come with per-page analytics, on Pro and higher plans. On other plans the Funnels card says so and shows nothing else.'
8672
+ },
8673
+ {
8674
+ path: '/marketing-and-automation/analytics/funnels',
8675
+ title: 'Funnels',
8676
+ heading: 'What a step can be',
8677
+ anchor: '#step-types',
8678
+ text: 'Only things your site already sees happen:\n| Step | Matches |\n| Viewed a page | A page at an exact path, or a path and everything under it (/blog and /blog/any-post) |\n| Submitted a form | A successful submission of one form, or of any form |\n| Made a booking | A booking for one service, or any booking — a free one when it is confirmed, a paid one when its payment settles |\n| Added a product to the cart | One product, or any product |\n| Placed an order | A storefront order that was paid |\n| Clicked a bar or popup | A click on one announcement bar or popup, or any |\n| Custom event | An event an interaction sends with Send an analytics event, by its name |\n| Email from the site | A person who identified themselves opened an email your site sent them, or clicked a link in one, when your email service reports it |\nThe step pickers list your site\'s real pages, forms, services, products and overlays, and a funnel can only be saved with steps your site has.\nAn Email from the site step is what lets a funnel show whether a follow-up worked — for example submitted the quote form → opened an email from the site → made a booking. It only ever counts people who submitted a form, because an email can only be tied to them.'
8679
+ },
8680
+ {
8681
+ path: '/marketing-and-automation/analytics/funnels',
8682
+ title: 'Funnels',
8683
+ heading: 'How a visit moves through a funnel',
8684
+ anchor: '#how-it-counts',
8685
+ text: 'For each visit, Aglyn looks at its steps in time order. A visit reaches step 1 the first time it matches step 1, reaches step 2 the first time it matches step 2 after that, and so on. A step done before the step ahead of it does not count, and a visit counts once per step no matter how often it repeats one.\nThe results show, over the dates you pick (up to 90 days):\n- Visitors at each step, as a bar, with the share of the previous step that reached it and the share of all visits that entered the funnel.\n- Drop-off — the visits at the previous step that never reached this one.\n- Median time from the previous step to this one.\n- Completed — the share of visits that entered and reached the last step.\n- By source — the same entered/completed counts by where the visit arrived from: its utmsource (and utmcampaign) when the link had them, otherwise the site that referred it, otherwise Direct.\nA visit belongs to the range it started in. Results are kept for a few minutes (a day for a range that has ended) so reopening the card is quick; Refresh recomputes them.'
8686
+ },
8687
+ {
8688
+ path: '/marketing-and-automation/analytics/funnels',
8689
+ title: 'Funnels',
8690
+ heading: 'What counts as a visit, and its limits',
8691
+ anchor: '#what-is-a-visit',
8692
+ text: 'A visit is one browser tab on your site, until it is closed. When a visitor\'s first step is recorded, their browser makes up a random visit id and keeps it in that tab\'s session storage — not a cookie, not shared with other sites, never derived from their address or device. Every step that tab takes is recorded under that id.\nThat means:\n- Two tabs are two visits, and a visitor who closes the tab and comes back tomorrow is a new visit. Nothing links one visit to another, or to a person — unless the visitor identifies themselves by submitting a form (see below).\n- Consent comes first. The visit id leaves the browser, so it is analytics storage: a step is recorded only once the visitor\'s cookie consent allows analytics. A visitor who declines, opts out or sends Global Privacy Control is never recorded, and steps taken before someone accepts are not recorded later. Funnels therefore count fewer visits than the traffic panel, and in regions where your site asks first, noticeably fewer.\n- Recording starts with your first funnel. A site with no funnels records nothing. Saving the first funnel turns recording on, and earlier visits cannot be measured. Deleting the last funnel turns it off.\n- Up to 60 steps per visit are recorded; a very long visit stops adding steps after that.\n- Visits are kept for 90 days and then deleted automatically.\n- Very busy sites: a result reads at most the 20,000 most recent visits in the range and says so when it stops there.\n- Visits from preview builds and from browsers marked as your own traffic are not recorded, the same as page views.'
8693
+ },
8694
+ {
8695
+ path: '/marketing-and-automation/analytics/funnels',
8696
+ title: 'Funnels',
8697
+ heading: 'Visitors who submitted a form',
8698
+ anchor: '#identified-visitors',
8699
+ text: 'When a visitor submits a form on your site during a recorded visit, that visit is tied to the email address they typed in the form. From then on:\n- All their recorded visits count as one visitor, so someone who submitted a quote form in one tab and booked in another the next day reaches both steps.\n- Emails your site sends them can be funnel steps — opened, or a link clicked.\n- They can be followed up when they drop off (see Act on a drop-off).\nAnonymous visitors are never tied to anyone. A visit is only tied to an address while the visitor\'s consent allows analytics, the address goes when the visit expires after 90 days, and erasing a person from your workspace deletes every visit tied to them.'
8700
+ },
8701
+ {
8702
+ path: '/marketing-and-automation/analytics/funnels',
8703
+ title: 'Funnels',
8704
+ heading: 'Create a funnel',
8705
+ anchor: '#create',
8706
+ text: '1. Open your site\'s Analytics page and find Funnels.\n2. Select New funnel, name it, and add steps with the pickers.\n3. Save. Saving needs a site admin or editor.\nCreate with AI {#create-with-ai}\nWhen Aglyn AI is available to your workspace, Create with AI turns a description — "people who read a blog post, then booked a consultation" — into a draft funnel. The draft uses only the pages, forms, services, products and bars or popups your site has; a step the model suggests that your site does not have is left out and listed. Nothing is saved until you review the draft and select Save. It uses AI credits like other generation.'
8707
+ },
8708
+ {
8709
+ path: '/marketing-and-automation/analytics/funnels',
8710
+ title: 'Funnels',
8711
+ heading: 'Act on a drop-off',
8712
+ anchor: '#act-on-drop-off',
8713
+ text: 'Below each step after the first, Act on this drop-off drafts an automation for the people who reached the step before it and did not go on. Pick:\n- After — how long to wait for them to go on: 1 hour, 1 day, 3 days or 7 days.\n- Then — send them a follow-up email, or create a CRM task for your team.\nThe automation is saved switched off on your site\'s Automation page. Edit its words there, then switch it on. It starts on the trigger Left a funnel, with conditions for this funnel, this step and this wait, and it can use the funnel\'s name, the step\'s name, the next step\'s name and the person\'s email.\nWho it reaches:\n- Only people who submitted a form on your site. Anonymous visitors are never followed up.\n- Only once per person, for each funnel, step and wait, and only if they had not reached the next step in any of their recorded visits.\n- A follow-up email is a mailing, not a reply: it carries its unsubscribe link and is never sent to someone who unsubscribed or whose address is suppressed.\n- People who dropped off in the last wait period before you created the automation are included; earlier ones are not.\nAglyn checks for drop-offs every 15 minutes, so a follow-up can arrive up to a quarter of an hour after its wait. Drafting needs a site admin or editor and a plan that includes automations. Add an Email from the site step after the step you follow up on to see in the funnel how many people the follow-up brought back.'
8714
+ },
8715
+ {
8716
+ path: '/marketing-and-automation/analytics/funnels',
8717
+ title: 'Funnels',
8718
+ heading: 'Ask AI about a funnel',
8719
+ anchor: '#ask-ai',
8720
+ text: 'On a funnel\'s results, Ask AI about this funnel opens Insights with a question about that funnel. Aglyn AI reads the funnel\'s figures — visitors, drop-off and time at each step, and every funnel\'s completion rate — and every number in the answer links back to them.'
8721
+ },
7987
8722
  {
7988
8723
  path: '/marketing-and-automation/analytics/google-analytics',
7989
8724
  title: 'Google Analytics events',
@@ -8066,14 +8801,14 @@ export const DOCS_SECTION_INDEX = [
8066
8801
  title: 'Insights',
8067
8802
  heading: 'Asking a question',
8068
8803
  anchor: '#asking-a-question',
8069
- text: 'Open the Assist panel on one of these pages and choose Ask about your numbers under AI jobs:\n- a site\'s Analytics page — traffic, top pages, where visits came from, forms, bookings, campaigns, A/B tests and store sales;\n- a site\'s CRM → Reports page — the same figures, for questions about where people came from and what they did;\n- a site\'s Data page, or your organization\'s Data page — your datasets.\nType your question, pick the window it covers (the last 7, 14, 30 or 90 days), and choose Ask. Answers usually take about a minute. You can close the dialog while you wait: the answer stays under AI jobs, where View answer opens it again.'
8804
+ text: 'Choose Ask a question on the Ask AI about these numbers card — on a site\'s dashboard, its Analytics page, and your organization\'s Sites page — or open the Assist panel on one of these pages and choose Ask about your numbers under AI jobs:\n- a site\'s dashboard or Analytics page — traffic, top pages, where visits came from, forms, bookings, campaigns, A/B tests, announcement bars and popups, store sales, automation runs, the CRM pipeline and deals closed, and funnels;\n- a site\'s CRM → Reports page — the same figures, for questions about where people came from and what they did;\n- a site\'s Marketing page — campaigns, the conversions they were credited with and the revenue they earned, beside the traffic, forms and store sales they drove;\n- a site\'s Automation page — its automations\' runs: how many succeeded and failed, and which failed most;\n- a site\'s Bookings page — bookings by service, and how many were canceled;\n- a site\'s Data page, or your organization\'s Data page — your datasets;\n- your organization\'s Sites page or CRM → Reports — the pipeline across every site, the deals won and lost, and your datasets.\nPipeline figures count only the deals the site can see: on a site, the deals shared with it; on your organization\'s pages, every deal. Automation runs are counted from the site\'s run history, never from what a run was about. Announcement bars and popups are counted since each was made — the views, clicks and dismissals the Overlays list shows — whatever window you pick.\nThe Conversions section and a campaign\'s report on the Marketing page also carry Ask AI about these numbers in their header, which opens the same dialog with a question about what that page shows — see Marketing with AI.\nType your question, pick the window it covers (the last 7, 14, 30 or 90 days), a'
8070
8805
  },
8071
8806
  {
8072
8807
  path: '/marketing-and-automation/analytics/insights',
8073
8808
  title: 'Insights',
8074
8809
  heading: 'How an answer is made',
8075
8810
  anchor: '#how-an-answer-is-made',
8076
- text: '1. The figures are read, never written. Aglyn AI chooses which of your figures answer the question — for example your traffic and your top pages — and Aglyn reads them the same way the console\'s own cards do. AI never writes a database query and never sees a single visitor, contact, order, booking or submission: only totals, counts and rates.\n2. Each insight cites its rows. Choose Show the figures under an insight to see the rows it was written from, and follow the link to the page those figures come from.\n3. Untraceable insights are left out. Every number an insight writes must appear in a row it cites — as the table shows it, or rounded. An insight that adds figures together, works out a rate of its own, says a figure rose when it fell, or names a person is left out, and the answer says how many were.\nWhen your figures cannot answer part of a question, the answer says so in one sentence rather than filling the gap.'
8811
+ text: '1. The figures are read, never written. Aglyn AI chooses which of your figures answer the question — for example your traffic and your top pages — and Aglyn reads them the same way the console\'s own cards do. AI never writes a database query and never sees a single visitor, contact, order, booking or submission: only totals, counts and rates.\n2. Each insight cites its rows. Choose Show the figures under an insight to see the rows it was written from, and follow the link to the page those figures come from.\n3. Untraceable insights are left out. Every number an insight writes must appear in a row it cites — as the table shows it, or rounded. An insight that adds figures together, works out a rate of its own, says a figure rose when it fell, or names a person is left out, and the answer says how many were.\nWhen your figures cannot answer part of a question, the answer says so in one sentence rather than filling the gap.\nA question asked about a site is also given that site\'s status, as a Site status table an insight can cite: whether the site is published, its address, and its published pages. A site with no visits yet is still live when it is published, so an answer never reads a lack of traffic as a site that has not launched. The window you pick is the period the figures cover, not a countdown to anything.'
8077
8812
  },
8078
8813
  {
8079
8814
  path: '/marketing-and-automation/analytics/insights',
@@ -8094,7 +8829,7 @@ export const DOCS_SECTION_INDEX = [
8094
8829
  title: 'Insights',
8095
8830
  heading: 'Privacy',
8096
8831
  anchor: '#privacy',
8097
- text: '- Only totals, counts, rates and labels are sent to the AI provider: page paths, referring sites and campaign tags; the names of forms, services, products and A/B tests; the subjects of campaign emails; and for a dataset, its field names and types and, in a breakdown, the values that at least three records share. Email addresses and phone numbers are removed from every label before anything is sent.\n- An answer is kept with your workspace for 180 days, like other AI jobs. Only the person who asked can open it; weekly insights can be opened by the people who reach the site.\n- Nothing is changed, published or sent to your contacts. The weekly email goes only to people in your workspace who asked for it.'
8832
+ text: '- Only totals, counts, rates and labels are sent to the AI provider: page paths, referring sites and campaign tags; the names of forms, services, products and A/B tests; the subjects of campaign emails, with conversions counted by kind and revenue by currency; and for a dataset, its field names and types and, in a breakdown, the values that at least three records share. Email addresses and phone numbers are removed from every label before anything is sent.\n- An answer is kept with your workspace for 180 days, like other AI jobs. Only the person who asked can open it; weekly insights can be opened by the people who reach the site.\n- Nothing is changed, published or sent to your contacts. The weekly email goes only to people in your workspace who asked for it.'
8098
8833
  },
8099
8834
  {
8100
8835
  path: '/marketing-and-automation/analytics/overview',
@@ -8108,7 +8843,7 @@ export const DOCS_SECTION_INDEX = [
8108
8843
  title: 'Analytics',
8109
8844
  heading: 'Pageview tracking',
8110
8845
  anchor: '#pageview-tracking',
8111
- text: 'A lightweight pageview beacon records visits into daily counters. The site dashboard shows a traffic panel summarizing your site\'s activity. Tracking is cookieless — no visitor IDs, no fingerprinting.'
8846
+ text: 'A lightweight pageview beacon records visits into daily counters. The site dashboard shows a traffic panel summarizing your site\'s activity. Tracking is cookieless — no visitor IDs, no fingerprinting. (Funnels are the one exception, and only with the visitor\'s analytics consent: they tie one browser tab\'s steps together.)'
8112
8847
  },
8113
8848
  {
8114
8849
  path: '/marketing-and-automation/analytics/overview',
@@ -8292,12 +9027,19 @@ export const DOCS_SECTION_INDEX = [
8292
9027
  anchor: '',
8293
9028
  text: 'Generate an email campaign with AI\nDescribe the email you want and AI generation writes a draft design: one email built from the email blocks, with three subject lines and three preheaders to choose between. Ask for a campaign instead and it writes the same design plus the draft campaign that would send it.\nBoth are drafts. Nothing is sent, scheduled or queued, and the campaign is aimed at nobody until you pick an audience yourself.'
8294
9029
  },
9030
+ {
9031
+ path: '/marketing-and-automation/email-campaigns/generate-with-ai',
9032
+ title: 'Generate an email campaign with AI',
9033
+ heading: 'Where to start it',
9034
+ anchor: '#where-to-start-it',
9035
+ text: '- An email design: on a site\'s Emails page, open Templates and press Create with AI, beside New template (or beside Create your first template while the list is empty). Write the brief, optionally pick the kind of email, and press Plan the email. A plan comes first: review it in the dialog or in AI jobs, and confirm it to build. Tick Also draft a campaign that sends it to get the campaign too (the button then reads Plan the campaign).\n- A campaign: on Marketing → Campaigns, press Create with AI beside Create campaign (or on the list while it is empty) — on a site\'s Marketing page, or on your organization\'s, where it asks which site the campaign is placed on. Describe it and press Write the campaign. When your plan sends no campaign email, the same button writes the email design on its own. See Marketing with AI.\nNothing is sent, and nothing is aimed at anybody, until you choose. The organization-wide Emails page has no Create with AI, because an email design belongs to one site.'
9036
+ },
8295
9037
  {
8296
9038
  path: '/marketing-and-automation/email-campaigns/generate-with-ai',
8297
9039
  title: 'Generate an email campaign with AI',
8298
9040
  heading: 'What you get',
8299
9041
  anchor: '#what-you-get',
8300
- text: 'An email design. It appears under Marketing → Email beside the templates you made by hand, and opens in the besigner exactly as those do. Every block is an email block — sections, text, buttons, images, dividers, spacers and product cards — so it renders the same way in every mail client.\nThree subject lines and three preheaders. They are stored with the design, the strongest as the subject and the preheader, the rest as alternatives. Change which one leads at any time, or write your own.\nA campaign, when you asked for one. A draft campaign holding that one email, with the subject and preheader already filled in. Open it from Marketing → Campaigns.'
9042
+ text: 'An email design. It appears on the site\'s Emails page, under Templates, beside the templates you made by hand, and opens in the besigner exactly as those do. Every block is an email block — sections, text, buttons, images, dividers, spacers and product cards — so it renders the same way in every mail client.\nThree subject lines and three preheaders. They are stored with the design, the strongest as the subject and the preheader, the rest as alternatives. Change which one leads at any time, or write your own.\nA campaign, when you asked for one. A draft campaign holding that one email, with the subject and preheader already filled in. Open it from Marketing → Campaigns, or from the finished job.'
8301
9043
  },
8302
9044
  {
8303
9045
  path: '/marketing-and-automation/email-campaigns/generate-with-ai',
@@ -8339,7 +9081,7 @@ export const DOCS_SECTION_INDEX = [
8339
9081
  title: 'Generate an email campaign with AI',
8340
9082
  heading: 'Where it runs',
8341
9083
  anchor: '#where-it-runs',
8342
- text: 'Email generation needs AI generation switched on for your workspace, the Email plugin switched on for the site, and permission to generate. Drafting a campaign also needs the Marketing plugin on and a plan that sends campaign email — see Billing & Plans. Without that, you can still generate email designs.'
9084
+ text: 'Email generation needs AI generation switched on for your workspace and for the site, the Email plugin switched on for the site, and permission to generate. Without them, Create with AI does not appear. Drafting a campaign also needs the Marketing plugin on for the site and a plan that sends campaign email — the dialog says so if either is missing — see Billing & Plans. Without that, you can still generate email designs.'
8343
9085
  },
8344
9086
  {
8345
9087
  path: '/marketing-and-automation/email-campaigns/generate-with-ai',
@@ -8425,6 +9167,13 @@ export const DOCS_SECTION_INDEX = [
8425
9167
  anchor: '#multiple-overlays-scheduling--page-targeting',
8426
9168
  text: 'The Marketing page manages any number of bars and popups, each with:\n- A schedule window (show from / show until) — run a bar only during a sale.\n- Page targeting — comma-separated paths, with /blog/ matching a whole section, plus a "never show on" exclude list.\n- An enable switch and a status chip (Live / Scheduled / Off).\nWhen several overlays match a page, the first bar and the first popup (by order) show. The single announcement bar and popup on the same page remain as your always-on default surfaces; configured overlays take priority over them.'
8427
9169
  },
9170
+ {
9171
+ path: '/marketing-and-automation/marketing-overlays/overview',
9172
+ title: 'Marketing Overlays',
9173
+ heading: 'Write and create overlays with AI',
9174
+ anchor: '#with-ai',
9175
+ text: 'With Aglyn AI on your workspace, two more controls appear here:\n- Write with AI, among the overlay editor\'s fields, writes a bar\'s text or a popup\'s headline, body and button label from a brief, and for a popup suggests one of the triggers above. It fills the fields unsaved; Save is still yours.\n- Create with AI, beside New bar and New popup, turns a brief into a new overlay that is saved switched off and opened in the editor, so no visitor sees it until you add its link and turn it on.\nNeither writes a link, the pages an overlay shows on, its schedule or its on-switch. See Marketing with AI.'
9176
+ },
8428
9177
  {
8429
9178
  path: '/marketing-and-automation/marketing-overlays/overview',
8430
9179
  title: 'Marketing Overlays',
@@ -8465,7 +9214,7 @@ export const DOCS_SECTION_INDEX = [
8465
9214
  title: 'Actions builder',
8466
9215
  heading: 'Create an action',
8467
9216
  anchor: '#create-an-action',
8468
- text: '1. Open the actions builder from Automation → Actions.\n2. Choose the event (the trigger).\n3. Choose the steps to run in response.\n4. Save.\nThat\'s it — no multi-step logic to manage. Reach for a workflow when you need several steps, branching, or composition.\nStart from a recipe {#recipes}\nBeside Add action, the Recipes menu lists four ready-to-edit CRM automations: Welcome a new lead, Follow up a won deal, Re-engage a stale lead and Tag by form. Choosing one opens the same editor already filled in — trigger, conditions and steps — with a line saying which recipe it started from; change anything, then save. Nothing is saved until you do. Tag by form asks for one of this site\'s forms first, because the trigger is keyed on it. What each recipe builds, step by step, is in Automations for the CRM → Recipes. An organization with several sites can also install a recipe on any of them, without the editor, from the organization\'s CRM → Settings → Recipes.\nCreate with AI {#describe-it}\nBeside Recipes, Create with AI drafts an automation from a sentence, using only the triggers and steps your plan includes. The draft arrives in the list switched off, with anything your site is missing left in square brackets for you to fill in. A saved automation\'s editor also has Explain it, and a failed run has Why did this fail?. See Draft and explain automations with AI.'
9217
+ text: '1. Open the actions builder from Automation → Actions.\n2. Choose the event (the trigger).\n3. Choose the steps to run in response.\n4. Save.\nThat\'s it — no multi-step logic to manage. Reach for a workflow when you need several steps, branching, or composition.\nStart from a recipe {#recipes}\nBeside Add action, the Recipes menu lists four ready-to-edit CRM automations: Welcome a new lead, Follow up a won deal, Re-engage a stale lead and Tag by form. Choosing one opens the same editor already filled in — trigger, conditions and steps — with a line saying which recipe it started from; change anything, then save. Nothing is saved until you do. Tag by form asks for one of this site\'s forms first, because the trigger is keyed on it. What each recipe builds, step by step, is in Automations for the CRM → Recipes. An organization with several sites can also install a recipe on any of them, without the editor, from the organization\'s CRM → Settings → Recipes.\nCreate with AI {#describe-it}\nBeside Recipes, Create with AI drafts an automation from a sentence, using only the triggers and steps your plan includes. The draft arrives in the list switched off, with anything your site is missing left in square brackets for you to fill in. A saved automation\'s editor also has Explain it, a saved action\'s has Change with AI and Fix with AI — each drafts a changed copy, switched off, and leaves the action as it is — and a failed run has Why did this fail?. See Automations with AI to draft, change, fix or explain one.'
8469
9218
  },
8470
9219
  {
8471
9220
  path: '/marketing-and-automation/workflows-and-actions/actions-builder',
@@ -8591,7 +9340,7 @@ export const DOCS_SECTION_INDEX = [
8591
9340
  title: 'Org automations',
8592
9341
  heading: 'Create one',
8593
9342
  anchor: '#create-one',
8594
- text: '1. At the organization level, open Automation → Org automations and choose Add org automation.\n2. Name it and pick the trigger event. Optionally add a filter or conditions — the same ones the actions builder offers.\n3. Choose where it runs on: Every site — including sites you add later — or Chosen sites, up to 30 of them.\n4. Add the steps, then save.\nOnly an organization owner, admin or editor creates and edits org automations. An organization holds up to 100 of them; deleting one frees its place.\nTriggers\nOrg automations start on what the server records about a person: Form submitted, New lead, Contact created, Contact changed stage, New booking, Member signed up, Member signed in, Deal moved, Deal won, Deal lost and CRM task completed. What each event carries for filters and conditions is listed under the filter field as you pick it.\nPage views and on-page events (clicks, scroll depth, exit intent) are not offered: they belong to one site\'s pages. Build those as actions on the site.\nSteps\nSend an email, Notify site admins, Enroll in a list, Assign to a campaign, Write to a dataset, Update a dataset record, the five CRM steps, Fire a custom event, Wait, Wait for something to happen and End the flow here.\nWhat is left out belongs to one site, so an org automation cannot run it:\n- Run a workflow — a workflow calls its own site\'s functions and variables;\n- Send a webhook — a webhook holds its own site\'s address and secret;\n- every in-page step — popups, drawers, menus, show and hide, CSS classes, custom HTML and JavaScript, analytics events, redirects and site alerts.\nTo hand over to something site-specific, use Fire a custom event: it fires on the site the org automation is running on, and that site\'s own actions can start on it.\nA dataset or a campaign is offered only w'
9343
+ text: '1. At the organization level, open Automation → Org automations and choose Add org automation.\n2. Name it and pick the trigger event. Optionally add a filter or conditions — the same ones the actions builder offers.\n3. Choose where it runs on: Every site — including sites you add later — or Chosen sites, up to 30 of them.\n4. Add the steps, then save.\nTo start from a description instead, choose Create with AI in the card\'s header: Aglyn AI drafts one and opens it in the editor, switched off, for you to place on sites and save. See Automations with AI.\nOnly an organization owner, admin or editor creates and edits org automations. An organization holds up to 100 of them; deleting one frees its place.\nTriggers\nOrg automations start on what the server records about a person: Form submitted, New lead, Contact created, Contact changed stage, New booking, Member signed up, Member signed in, Deal moved, Deal won, Deal lost and CRM task completed. What each event carries for filters and conditions is listed under the filter field as you pick it.\nPage views and on-page events (clicks, scroll depth, exit intent) are not offered: they belong to one site\'s pages. Build those as actions on the site.\nSteps\nSend an email, Notify site admins, Enroll in a list, Assign to a campaign, Write to a dataset, Update a dataset record, the five CRM steps, Fire a custom event, Wait, Wait for something to happen and End the flow here.\nWhat is left out belongs to one site, so an org automation cannot run it:\n- Run a workflow — a workflow calls its own site\'s functions and variables;\n- Send a webhook — a webhook holds its own site\'s address and secret;\n- every in-page step — popups, drawers, menus, show and hide, CSS classes, custom HTML and JavaScript, analytics events, redirects and site alerts.\nTo '
8595
9344
  },
8596
9345
  {
8597
9346
  path: '/marketing-and-automation/workflows-and-actions/org-automations',
@@ -8738,7 +9487,7 @@ export const DOCS_SECTION_INDEX = [
8738
9487
  title: 'Add-ons',
8739
9488
  heading: 'Aglyn AI',
8740
9489
  anchor: '#aglyn-ai',
8741
- text: 'Aglyn AI is the generative add-on: with it on, the assistant builds for you — pages, components, emails, campaigns, products and more — rather than only answering questions about them. It is bought once for the workspace, on any paid plan, and applies to every member who has the permission to generate. What each door does is under Aglyn AI.\n- Everything it builds is a draft. The add-on cannot publish a page, change a live one or send an email. It writes drafts and unpublished versions, which a person reviews and publishes through the buttons that already exist — see the draft rule.\n- One pool, one meter. The add-on adds a band of AI credits to the band your plan already includes, every month. There is no second meter: the AI credits meter on Billing → Usage shows your plan\'s credits and the add-on\'s as one figure, and the same overage rate, stop switch and monthly ceiling apply to the whole band — see AI credits and overage.\n- Priced by plan. The add-on\'s monthly price and the credits it adds both rise with the plan. The figures are on aglyn.com/pricing and in Billing before you confirm; on annual billing it bills yearly with the plan, like every add-on. Enterprise workspaces carry generative building in their agreement instead of buying it.\n- Starter widens a band it already has. Starter includes its own monthly AI credits, and credits past them are sold at the same rate as Pro — so the stop switch and the ceiling are on its billing page with or without the add-on. Adding Aglyn AI increases the band and opens generative building.\n- Free workspaces do not buy it. They generate against the monthly taste instead, which stops at its band and never bills.\n- Removing it takes effect at the end of the period you already paid for, like every add-on removal. Then the band shrin'
9490
+ text: 'Aglyn AI is the generative add-on: with it on, the assistant builds for you — pages, components, emails, campaigns, products and more — rather than only answering questions about them. It is bought once for the workspace, on any paid plan, and applies to every member who has the permission to generate. What each door does is under Aglyn AI.\n- Everything it builds is a draft. The add-on cannot publish a page, change a live one or send an email. It writes drafts and unpublished versions, which a person reviews and publishes through the buttons that already exist — see the draft rule.\n- One pool, one meter. The add-on adds a band of AI credits to the band your plan already includes, every month. There is no second meter: the AI credits meter on Billing → Usage shows your plan\'s credits and the add-on\'s as one figure, and the same overage rate, stop switch and monthly ceiling apply to the whole band — see AI credits and overage.\n- Priced by plan. The add-on\'s monthly price and the credits it adds both rise with the plan. The figures are on aglyn.com/pricing and in Billing before you confirm; on annual billing it bills yearly with the plan, like every add-on. Enterprise workspaces carry generative building in their agreement instead of buying it.\n- Starter widens a band it already has. Starter includes its own monthly AI credits, and credits past them are sold at the same rate as Pro — so the stop switch and the ceiling are on its billing page with or without the add-on. Adding Aglyn AI increases the band and opens generative building.\n- You can see where it is used before you buy it. On a paid plan without it, Create with AI still shows on the Pages, Templates, Layouts, Forms, Components, Automation, Functions & Variables and email Templates pages, on Products, and on Marke'
8742
9491
  },
8743
9492
  {
8744
9493
  path: '/workspace-and-billing/billing-and-plans/add-ons',
@@ -8878,7 +9627,7 @@ export const DOCS_SECTION_INDEX = [
8878
9627
  title: 'Billing & Plans',
8879
9628
  heading: 'Tiers & entitlements',
8880
9629
  anchor: '#tiers--entitlements',
8881
- text: 'Prices live on one page Current prices — monthly, annual, transaction fees and per-unit overage rates — are on aglyn.com/pricing, and your own plan and next invoice are in Billing in the console. This page explains how billing WORKS; it deliberately does not restate the numbers, because a second copy is a copy that goes stale.\n| Plan | Commerce |\n| Free | Build & publish only — no selling |\n| Starter | Sell products, with the highest transaction fee of the paid tiers |\n| Pro | More products, a lower fee, POS, abandoned-cart recovery, reviews, dropshipping |\n| Business | More products again, a lower fee, subscriptions & paywalls, gift cards |\n| Scale | Higher product and site limits, lower fee again |\n| Advanced | Unlimited products, no transaction fee, high-volume commerce & API |\n| Agency | Many sites under one organization, white-label |\n| Enterprise | Twice Agency\'s capacity by default and more by agreement, SSO, white-label, no transaction fee |\nTransaction fees are Aglyn platform fees on the sales you take through your site — storefront orders, paid memberships and paid bookings alike — separate from Stripe\'s payment-processing fees. Upgrading is the way to reduce them.\nEvery plan also includes an amount of monthly traffic — 2 GB on Free, rising to 790 GB on Enterprise by default (an agreement can set more). Passing it is metered and billed on a paid plan, and pauses the site until the start of next month on Free. See Bandwidth for the table and for what a paused site shows a visitor.\nVideo, audio, file downloads and other media served from our servers count 1.6× toward bandwidth, because serving them costs more than serving pages. See how usage is counted.\nLinks on a new Free site {#leaving-notice}\nFor a Free workspace\'s first 14 days, its sites send links and red'
9630
+ text: 'Prices live on one page Current prices — monthly, annual, transaction fees and per-unit overage rates — are on aglyn.com/pricing, and your own plan and next invoice are in Billing in the console. This page explains how billing WORKS; it deliberately does not restate the numbers, because a second copy is a copy that goes stale.\n| Plan | Commerce |\n| Free | Build & publish only — no selling |\n| Starter | Sell products, with the highest transaction fee of the paid tiers |\n| Pro | More products, a lower fee, POS, abandoned-cart recovery, reviews, dropshipping |\n| Business | More products again, a lower fee, subscriptions & paywalls, gift cards |\n| Scale | Higher product and site limits, lower fee again |\n| Advanced | Unlimited products, no transaction fee, high-volume commerce & API |\n| Agency | Many sites under one organization, white-label |\n| Enterprise | Twice Agency\'s capacity by default and more by agreement, SSO, white-label, no transaction fee |\nTransaction fees are Aglyn platform fees on the sales you take through your site — storefront orders, paid memberships and paid bookings alike — separate from Stripe\'s payment-processing fees. Upgrading is the way to reduce them.\nEvery plan also includes an amount of monthly traffic — 2 GB on Free, rising to 790 GB on Enterprise by default (an agreement can set more). Passing it is metered and billed on a paid plan, and pauses the site until the start of next month on Free. See Bandwidth for the table and for what a paused site shows a visitor.\nVideo, audio, file downloads and other media served from our servers count 1.6× toward bandwidth, because serving them costs more than serving pages. See how usage is counted.\nEach site also holds a number of saved forms and reusable components: one of each on Free, more on every paid'
8882
9631
  },
8883
9632
  {
8884
9633
  path: '/workspace-and-billing/billing-and-plans/overview',