The industry-standard accessibility rule engine (axe-core — the one under Lighthouse), bundled INSIDE the extension and run locally on the live DOM: nothing leaves the page, no remote code. Hundreds of WCAG A/AA checks on top of qa_run_audit's own set, narrowed to WCAG-tagged rules so every violation maps to a criterion. Returns violations with impact, WCAG tags, help URL and up to 10 offending selectors each. Read-only. Needs an extension build that carries the engine — an older build answers "unknown command: axe" (reload the extension after updating).

Target tab (from qa_tabs); omit for the active tab

Run the axe-core rule engine on the page

Click an element on the page under test — by a qa_snapshot ref, by a CSS selector, or by the control's accessible `name` (the one to use right after a fill, since filling re-renders the step and staleness is what makes a ref refuse). Sends the full pointer sequence (pointerdown → mouseup → click), so component libraries that listen for pointerdown — Radix, shadcn, MUI — react to it like a real click. Scrolls the element into view first, and refuses a target that matches nothing or has zero size rather than silently doing nothing. Returns what the click CHANGED — what appeared, disappeared or updated once the page settled — so you do not need a follow-up qa_snapshot to find out whether it did anything. `changed: null` means the page did not move, which is itself the answer. On a recent extension build the reply also carries `announced` — what the page's live regions (aria-live / role=status / role=alert) actually spoke during the settle window, or null if they stayed silent: a toast that appeared in `changed` but not in `announced` is invisible to a screen reader (WCAG 4.1.3). Requires Qiksy Pro and the one-time “Agent control” confirmation in the panel; without both the extension answers pro-required / consent-required and does nothing.

Click the control with THIS accessible name — "Next", "Submit application", "Add member". Use it instead of a ref right after filling: a fill re-renders the page, which makes the ref you took before it stale (the extension refuses a stale ref rather than clicking the wrong thing). This resolves the name against a fresh snapshot, so it cannot go stale.

A ref from qa_snapshot (e.g. "e12") — preferred over selector; unique where a selector is ambiguous

Narrow a `name` match to one role, e.g. "button", "link", "tab", "radio"

CSS selector of the element to click

Click an element (Pro)

Close one tab or a list of them — how you tidy up the isolated logins when a matrix run is finished. Returns which ids closed and which were already gone. Requires Qiksy Pro and the one-time “Agent control” confirmation in the panel; without both the extension answers pro-required / consent-required and does nothing.

A single tab to close

Several tabs to close, e.g. every isolated login from qa_tabs

Close tabs (Pro)

The browser's OWN dialogs — “Leave site? Changes you made may not be saved”, confirm(), alert(), prompt() — are drawn outside the document, so no click of any kind can reach their buttons. Nothing on this bridge can press them and nothing in any page can. What IS reachable is the page's REQUEST for them, and that is what this changes: `beforeunload:true` stops the app from asking, so the navigation simply proceeds; `confirm:"accept"|"dismiss"` decides what confirm() returns; `alert:true` swallows alerts; `prompt` supplies the string (or null to cancel). op:'list' is free and reads the policy in force; setting one needs Pro + the Agent control consent, because an auto-accepted confirm can be the one in front of Delete. SCOPE: this tab, until it closes; it survives reloads of it. EVERY suppressed dialog is logged as a finding carrying the question the page asked and the answer given — so never report that the app stopped asking. It asked; Qiksy answered. Clear it (op:'clear') as soon as the flow is through.

true = swallow alert() instead of blocking on it

true = let navigation through without the browser’s “Leave site?” prompt

What confirm() returns; null removes the override

Default 'set'

What prompt() returns; null cancels it

Decide what the page’s own native dialogs do

Full qa-export/v1 bundle for a page: findings (with selectors), failed requests (with server error bodies), detected form structure, recorded repro steps, env, and isolated-login name. Read this, then fix the underlying issues. Pass tabId (from qa_tabs) to target a specific tab / isolated login.

QA export

Hand the page a plain JSON object — { "Field label": "value" } — and it fills the form in ONE call. No refs, no snapshot of your own: this takes its own snapshot, matches each key against the fields' accessible names (exact, then truncated, then contains) and passes the whole lot to the batch filler, so every control kind is covered — text, native and CUSTOM selects, typeahead comboboxes, date pickers, checkboxes (true/false), radios, sliders, rich text. This is the shape of the JSON behind the panel's own `{ }` editor and its ⚡Fill button, so a dataset you write here reads the same way a human would edit it. Reach for this when you ALREADY know the data — from a ticket, a persona, a CSV row — and for a form you have not mapped: it is one call instead of snapshot-then-batch. Use qa_snapshot + qa_type_many instead when you need to choose targets deliberately (duplicate labels, one specific control among many). Keys that match nothing come back as `unmatched`, together with the field names the page actually has, so the next call can use the right key without another round trip. DATE FIELDS BUILT FROM SECTIONS (MUI X DateField/DatePicker: separate Day / Month / Year spans the component owns) cannot be written to at all — the answer will say so under `verified`, and the way in is the calendar: click the "Choose …" button, switch to the year view, pick the year, step the month, click the day. A value of "click" PRESSES the thing instead of filling it — for the parts of a step that take no value: a chip, a custom radio (div role=radio), a switch, a toggle button. { "Climate": "click", "Medium": "click" } goes in the same batch as the text fields. REPEATED LABELS: a form built from a repeated component gives several controls the identical label — address them as "Full name", "Full name#2", "Full name#3", which is the same #N notation the panel's own dataset uses, so a dataset copied out of the `{ }` editor works as written. ONE CALL PER WIZARD STEP: pass `advance: "Next"` and this presses that control after the fill — but only when the fill was clean. It is NOT pressed if an entry came back ok:false, if a key matched nothing, or if a value is still wrong after the repair, and the reply says which of those it was. Whether the page really advanced is decided by the DIFF the click produced (a step swap makes many nodes appear AND disappear), never by the click answering ok: a Next that is disabled until the step validates accepts a click and does nothing — that case is caught before the click, from the control's own state, and comes back as `advanced.ok:false` with `stillNeeded`. When it did advance, `next` carries the FIELD NAMES of the step you are now on, so the following step costs no qa_snapshot of your own; pass next:false to leave them out. dry_run:true resolves the keys and fills nothing — read-only, and the cheap way to check a dataset against a page (with `advance` set it reports `wouldAdvance` and presses nothing). Requires Qiksy Pro and the one-time “Agent control” confirmation in the panel; without both the extension answers pro-required / consent-required and does nothing.

After the fill, click the control with THIS accessible name — "Next", "Continue", "Submit". Resolved by name against a snapshot taken at that moment (a fill re-renders the step, which is what makes a ref taken earlier click the wrong button), skipped entirely when the control reports itself disabled, and refused when anything about the fill was not clean. The reply's `advanced.ok` tells you whether the page actually moved, judged by the click's diff.

Resolve the keys and report what would be filled, without touching the page

The dataset: { "Initiative name": "Test run", "Country": "Ukraine", "Start date": "2026-08-01", "I agree": true }

Default true when `advance` is set: ride the NEXT step's field names back in the same reply (`next.fields`, plus its title and what its forward control is called), so the step after this one costs you no qa_snapshot. Pass false when you do not need them.

Target tab (from qa_tabs); omit for the active tab

Default true: after the batch, read the page back and re-write any field whose value did not actually land, one at a time and re-found by name. This is what makes MUI-style multi-section fields and masked inputs work; pass false to skip the check.

Limit the matching to one form / dialog / step — the `selector` of a container node from a snapshot

Fill a form from a JSON of labels and values (Pro)

Findings on a page (console/JS/network/a11y/markup/submit) — each with a CSS selector and detail. Filter by severity; pass tabId (from qa_tabs) to read a specific tab / isolated login.

Severity filter

QA findings

Put a tab in front of the person — activate it and raise its window — so they are looking at what you are about to show. This is the WALKTHROUGH verb, and it is the one thing Qiksy otherwise refuses to do: everything else works in whatever tab is already in front, which is why a demo asked for from an editor used to land in a tab nobody was watching. Use it when you have been asked to SHOW, not to test — then narrate with qa_spotlight (its `label` is what turns a sequence of clicks into "step 3 of 6"). Do NOT call it to make your own work easier: taking someone's screen mid-sentence is the behaviour this product exists to avoid. Scoped to the app under test and its isolated logins (see qa_tabs) — it cannot reach the rest of the browser. Free: it neither reads nor changes the app.

Which tab to bring forward (from qa_tabs). Omit for the app under test.

Bring a tab in front of the human

The keyboard route as ONE call: presses Tab repeatedly and records where focus actually lands, then compares that trail against the interactive elements the accessibility tree claims. This is the accessibility question a click can never answer — Qiksy clicks teleport to an element, a keyboard user has to REACH it. Reports: the focus trail; interactive elements that never got focus (the div-button a Tab user can never reach); a suspected focus TRAP when the same short cycle of names repeats without the walk closing; and order-vs-geometry suspects — consecutive stops where focus jumps far UP the page, the classic broken tab order. Honest limits, stated because this tool feeds audits: matching is by accessible NAME (the press reply carries no ref), so duplicate names can mask a missed element; focus VISIBILITY is not judged here (that is qa_styles on a stop that interests you); and the walk changes the page's focus for real, so run it before filling, not mid-form. Requires Qiksy Pro and the one-time “Agent control” confirmation in the panel; without both the extension answers pro-required / consent-required and does nothing.

Tab presses before giving up (default 80). A page that does not close its cycle within this is reported, not guessed at.

Walk the page the way a keyboard user does — Tab by Tab (Pro)

Override what the app RECEIVES from the network — the thing DevTools calls a local override, driven from here. Set a rule and the page's next matching fetch/XHR is answered by it: your status, your body, optionally after a delay, or as an outright network failure. This is how you test the paths a server will not produce on demand: an empty list, a 500, a 403 that should log the user out, a 30-second response that should show a spinner, a malformed payload, a field the API does not return yet. op:'list' is free and READS the rules in force; set / remove / toggle / clear change what the app sees and need Pro + the Agent control consent, because an app fed an invented 200 can persist it. MATCHING: `url` is a substring of the full URL, or `/regex/flags` when you wrap it in slashes; `method` defaults to any. First matching enabled rule wins. `times` spends the rule after N answers (leave it out for unlimited) — that is how you make the FIRST call fail and the retry succeed. LIFETIME: a rule belongs to ONE TAB, survives reloads of it, and is gone when it closes. It is not in force in any other tab. WHAT IT DOES NOT CATCH, so you do not debug a rule that was never consulted: only the page's own fetch/XHR in the top frame. Not the HTML document itself, not images/scripts/stylesheets, not WebSocket or EventSource, not sendBeacon, not requests made inside an iframe or from the page's own service worker. Mocked responses are logged as `(mocked)` in the session, the HAR and the report — a value you invented is never presented as the server's. Remember to clear rules when you are done; a forgotten mock is the most expensive thing here.

Response body, verbatim. JSON-looking bodies get a JSON content-type unless you set one

Hold the answer back this long — for spinners and timeouts (max 60000)

For op:'toggle'

Fail at the network level (fetch rejects, XHR fires error) instead of answering

Response headers

Rule id, for remove / toggle / editing an existing rule

GET / POST / … — omit to match any method

Why this rule exists — shown to the human in the panel

Default 'set'

Status to answer with (default 200)

Apply at most N times, then let the real request through

Substring of the request URL, or /regex/flags

Answer a request from a rule instead of the server

Point a tab at a URL and wait until it is loaded and Qiksy is live again — the ready-wait is built in, so the next step can run straight after. Use it to jump between steps of a flow that are not reachable by clicking. Requires Qiksy Pro and the one-time “Agent control” confirmation in the panel; without both the extension answers pro-required / consent-required and does nothing.

Target tab (from qa_tabs); omit for the active tab

Absolute http(s) URL

Navigate a tab (Pro)

Open a tab with its OWN private session — separate cookies, localStorage, IndexedDB — so a second (or third) user can be logged in at the same time in the same browser. Returns its `tabId`; pass that to any tool to run the whole flow as that user, while the first login keeps working untouched. This is how you test a hand-off: submit as one role here, then verify it as another role there, side by side. Requires Qiksy Pro and the one-time “Agent control” confirmation in the panel; without both the extension answers pro-required / consent-required and does nothing.

Open this many (max 12); unnamed ones become user-1, user-2, …

Name for a single session, e.g. "admin"

Open SEVERAL at once, named: ["admin","manager","member","viewer"] — one tab each, all live side by side

Absolute http(s) URL to open in the isolated tab(s)

Open an isolated login tab (Pro)

Open (or close) the Qiksy side panel on a tab and optionally jump to a tab: 'forms' | 'findings' | 'tour' | 'tools' | 'history' | 'roles'. Controls Qiksy's OWN UI only — it does not touch the page under test. Set open:false to close.

true to open, false to close

Which panel tab to show

Open Qiksy panel

Put an EXACT date into a date field in ONE call — including the ones a value cannot be written to. It tries the cheap way first (type the date, press Enter, check it stuck), and only if that fails does it open the picker and steer it: the year view for MUI X, the clickable year in the header for Ant Design, the month/year dropdowns for react-datepicker, and plain arrows for anything else — stepping until the calendar header agrees, then clicking the day. Use this instead of writing to a date field whose value never sticks: MUI X DateField is three contenteditable sections the component rebuilds from its own state, so a written "14" can land in the YEAR and the day stay empty. Returns `via` (typed or calendar) and a `trail` of what it actually had to do, so a picker this does not recognise is visible rather than silent. Requires Qiksy Pro and the one-time “Agent control” confirmation in the panel; without both the extension answers pro-required / consent-required and does nothing.

The date as dd/mm/yyyy — the exact one the form must end up with

The field's accessible name, e.g. "Owner date of birth"

Name of the button that opens the picker, when the field itself does not (MUI renders "Choose <field name>")

Set a date, whatever library owns the calendar (Pro)

One call for the widgets where a single value takes several interactions: an Ant Design Cascader (country → region → city, a column per level), a TreeSelect with collapsed branches, a menu of submenus, any drill-down. Pass the path as it reads on screen and it opens the control, clicks each level on a FRESH snapshot (opening a level is exactly what re-renders the popup), expands a branch that hides its children, and closes up afterwards. A level that never appears is reported with the levels that did, so you can see where the path diverged from the page instead of guessing. Requires Qiksy Pro and the one-time “Agent control” confirmation in the panel; without both the extension answers pro-required / consent-required and does nothing.

Leave the popup open afterwards. Rarely needed now that `paths` exists.

The control's accessible name, e.g. "Delivery location"

The levels in order, e.g. ["Ukraine","Kyiv oblast","Kyiv"]. Pass this OR `paths`.

SEVERAL values from one control, walked inside ONE opening — e.g. [["Europe","Poland"],["Europe","Germany"]] for a checkable tree. Use this rather than calling the tool twice: a second call clicks the control to open it, which on an already-open popup CLOSES it, and live that left a tree with two picks holding none. A shared parent is not re-clicked (that would toggle the whole branch off).

Choose a value that lives across several levels (Pro)

Both ends of a date range in one call, for a control that owns two inputs — Ant Design's RangePicker and its equivalents. Not the same as two qa_pick_date calls: the control walks from the start panel to the end panel by itself, and approaching it a second time from cold restarts the range on the start input, which is how a range ends up half-set. The start goes in through the normal single-date route (so every library it knows still applies), then the panel — still open — is steered to the end date by the same recipe with the opening click dropped. Reports a `trail` of what it clicked, and if the panel closed after the start it says so instead of pretending: some pickers do, and then the end date is its own field ("End date") for a plain qa_pick_date. Requires Qiksy Pro and the one-time “Agent control” confirmation in the panel; without both the extension answers pro-required / consent-required and does nothing.

The start, dd/mm/yyyy

The control's accessible name — for Ant this is usually the START input's name, e.g. "Start date" or the field's label

Target tab (from qa_tabs); omit for the active tab

The end, dd/mm/yyyy

Set a date RANGE that lives in one control (Pro)

One call for a whole list of tags on a control that has no option list to pick from — Ant Design's Select in `mode="tags"`, and every chips input built the same way: the value is typed and committed with a key. Per tag it types, VERIFIES the text is still in the field, then presses the key, on a ref re-resolved each time. The verification is the point and it is not defensive coding: when a tag commits, the component clears its own search input, the re-render can wipe a value written a moment earlier, and the key then re-submits the PREVIOUS text — which in tags mode toggles that tag back OFF. That is how a form ends up with the tag you added first missing. It also never clicks the field first: a click moves the caret out of the component's search input and the text goes nowhere. Returns which tags went in and, for any that did not, what the field was holding instead. If a control refuses every tag it is probably NOT in tags mode — it only accepts values from its list, and qa_type with the option text is the right verb. Requires Qiksy Pro and the one-time “Agent control” confirmation in the panel; without both the extension answers pro-required / consent-required and does nothing.

The key that commits a tag. Default "Enter"; some components use "," or "Tab".

The control's accessible name, e.g. "Product tags"

The tags to add, in order — e.g. ["chilled","ambient","frozen"]. Never repeat one: a second submit of the same text removes it.

Add tags / chips to a field that CREATES its values (Pro)

A time in one call on a column-based picker — Ant Design's TimePicker and its equivalents. Needed because the cells are bare list items with NO accessibility role, so the snapshot cannot see them, and the ordinary fill path misreads the control as a date field ("calendar did not open — typed an ISO date instead") and leaves it empty while reporting success. This reads each column's text, finds which entry is your value and clicks THAT child, then presses the panel's own OK — which is not optional: without it the value stays provisional and the field ends up empty. Reading the column instead of computing an index is deliberate: the minute step is configurable and guessing it would be a bug. Requires Qiksy Pro and the one-time “Agent control” confirmation in the panel; without both the extension answers pro-required / consent-required and does nothing.

The control's accessible name, e.g. "Weekly call time"

The time as the picker shows it — "14:30", or "14:30:00" for a picker with a seconds column

Set a time on a picker whose cells have no role (Pro)

Dispatch a keyboard key (keydown/keypress/keyup) — Enter to submit, Escape to close, Tab to move focus. Without a selector it goes to whatever currently has focus, like a real keyboard. Like qa_click, it returns what changed once the page settled. On a recent extension build the reply also carries `focus` — the element that ACTUALLY holds focus after the key (name, role, selector, box), which is how you follow a Tab route or catch focus landing somewhere unnamed — and `announced`, what the live regions spoke (null = they stayed silent). Requires Qiksy Pro and the one-time “Agent control” confirmation in the panel; without both the extension answers pro-required / consent-required and does nothing.

Key value, e.g. "Enter", "Escape", "Tab", "a"

Optional target (a qa_snapshot ref); defaults to the focused element

Optional target (CSS); defaults to the focused element

Press a key (Pro)

Identify ONE unfamiliar control and get back the verb that drives it. Judges it first by shape — role, tag, name, state and its neighbours — which settles a sectioned date field, a file input, a switch, a slider or a plain field without touching the page at all. When the shape says nothing, which is what happens to a widget hand-rolled from <div>s (role "generic", no name, no state), it clicks once and reads what the page DID: day numbers or a grid appeared → a calendar, two options → a select however it is built, checkboxes → a tree, a menu, a modal, or the most useful verdict of the set — it went `expanded` and the tree gained NOTHING, which means the popup is portalled markup with no roles and must be addressed by CSS selector (Ant Design). Then it presses Escape so the form is left as it was found. Use it on the ONE field that just refused a value, not on every field: a snapshot already classifies the whole page (`componentLibraries` + `hints`), and driving is what the other verbs are for. Do not aim it at a Submit or Next — that click advances the page and Escape cannot take it back; the reply says `pageMoved` when it happened. Requires Qiksy Pro and the one-time “Agent control” confirmation in the panel; without both the extension answers pro-required / consent-required and does nothing.

Press Escape afterwards to close whatever opened. Default true; pass false when you want to keep the popup open and read it

The control's accessible name, as a human reads it on screen

CSS selector — for a control with no accessible name at all, which is the case this tool exists for

What kind of widget is this, and how do I drive it? (Pro)

Return the RENDERED text of the page under test, or of a single element named by a qa_snapshot ref or a CSS selector. This is the companion to qa_snapshot: that one maps what you can ACT on (roles, names, refs) and caps every name at 80 characters, so anything longer — a one-time code in an email, an error paragraph, a generated invoice number — is invisible to it. Uses innerText, so hidden branches and a mail thread's collapsed quoted history stay out. Read-only: it executes nothing and returns text, capped (default 4000 chars, max 20000).

Cap the returned text (default 4000, max 20000)

A ref from qa_snapshot (e.g. "e12") — preferred when you already have one

CSS selector; omit both to read the whole page body

Target tab (from qa_tabs); omit for the active tab

Read the text of a page (or one element)

Replay a saved flow on the page as it is NOW. Per step it takes its own snapshot, matches every field by accessible name (exact, then truncated, then contains, then the stored cssPath), fills the whole step in ONE batch, attaches the step's uploads, and clicks the advance control — so a step costs you one call instead of a snapshot plus a call per field. Refs are never reused across runs; the names are. A field the page no longer has comes back under `missing` instead of failing the step, so you can see what drifted and fix that one field by hand. Override any value with `values` — same recipe, different data (that is how one saved flow becomes a data-driven test). START WITH dry_run:true: it resolves everything and changes nothing, needs neither Pro nor consent, and tells you whether the recipe still fits. IT ACTS: with `all` it walks every remaining step and clicks each advance control, so if the last step's advance is Submit, it submits. On anything irreversible, run the steps one at a time. Requires Qiksy Pro and the one-time “Agent control” confirmation in the panel; without both the extension answers pro-required / consent-required and does nothing.

Replay from `step` to the end, stopping at the first step that cannot be resolved

Resolve the targets and report the plan without touching the page. Read-only.

The recipe name (or part of it) from qa_recipe_list

Which step to replay, 1-based. Default 1.

Override stored values, keyed by the field name in the recipe — { "Initiative name": "Test run 2" }

Replay a saved recipe, a step at a time (Pro)

The flows already saved on this machine, newest first: name, host, step count, and the fields of the first step so you can tell them apart. Worth ONE call at the start of any form-heavy task — if a recipe for this host exists, replaying it beats rediscovering the form. Local only, no browser, no Pro.

Only recipes filed under this project

Only recipes carrying this tag

Only recipes whose host matches this URL

List the saved recipes

Write what you just did on this page to a JSON recipe on this machine, so the NEXT run replays it instead of rediscovering it. Call it with just a name and it builds the recipe from what this session actually filled: the fields (by accessible name, with the cssPath as fallback), the uploads, and the control you clicked to move on — folded into steps, since a click after a group of fills is what ends a step of a wizard. Pass `steps` yourself to write a recipe by hand, or to correct one. Do this at the END of any flow that took more than a few calls — a long multi-step form, a signup, a wizard — and say so in one line to the human: the recipe is a file they own, at the path this returns, editable and deletable by hand. Local only: writes a file, touches no browser, needs no Pro.

A name you will recognise later, e.g. "new initiative form" — the file is named after it

Anything the replay should know that the fields do not say — a precondition, a role to be signed in as, a step that only appears sometimes

Which product or client this flow belongs to. It becomes a FOLDER, and it is what qa_suite_run groups by. Host is not enough on its own: staging and production are two hosts and one project, and two products behind one domain are one host and two projects.

Write the steps explicitly instead of deriving them from this session

The control that moves to the next step — Next, Continue, Save

How to set it. `date` replays through qa_pick_date (value dd/mm/yyyy), `path` through qa_pick_path (levels separated by ">"); both are what a written value cannot do.

What the classifier judged this control to be — "date-sections", "checkable-tree", "select-trigger". Stamped automatically when the recipe is built from this session; it is what stops the next run rediscovering that a calendar cannot be typed into.

The field's accessible name — the durable key across runs

Snapshot role, to disambiguate a name shared by a label and a control

cssPath fallback, used when no name matches

Labels for picking a subset later — ["smoke"], ["billing","regression"]. A suite can be run by tag instead of by name.

The flow's starting URL. Defaults to the page of the last snapshot; used to scope the journal to this host and to remind you where to start.

Save the flow you just drove, as a replayable recipe

Reload the tab as it stands — same address, no URL to pass — and wait until it has loaded AND Qiksy is live in the new document, so the next call needs no sleep. Use it after anything a fresh load fixes: the extension updated under an open tab, a mock was cleared, storage was written by hand, the app wedged. The browser performs it, not the page's own script, so it works even when that script is already dead — which is exactly the case a reload is for. Pass bypassCache for the hard reload (Ctrl/Cmd+Shift+R) when you suspect a stale bundle. Requires Qiksy Pro and the one-time “Agent control” confirmation in the panel; without both the extension answers pro-required / consent-required and does nothing.

Hard reload: re-fetch the page and its assets instead of using the browser cache. Default false.

Target tab (from qa_tabs); omit for the active tab

Reload a tab (Pro)

Generate Qiksy's self-contained HTML report — coverage stats, per-page table, steps with screenshots, findings — and return the HTML. Pass `spec` to make it answer the question the TICKET asked: give it the story and your verdict on each acceptance criterion, and the report leads with those, rendered next to the evidence Qiksy collected itself (errors, failed requests with server bodies, screenshots). That turns a log into a deliverable a developer or a client can read. You supply the verdicts — you are the one who read the story; Qiksy supplies the proof. Requires History recording to have captured steps; otherwise returns a note.

Write the report HERE instead of returning it. An absolute path, or one relative to where the bridge process runs. STRONGLY PREFERRED: the report is a self-contained HTML document with embedded screenshots and routinely runs to hundreds of kilobytes — returning it inline spends your context on bytes you were going to save to a file anyway. You get back the path, the size and the report title.

Acceptance criteria + verdicts to lead the report with

What you actually observed

Criterion id, e.g. "AC-3"

Where, if it is element-specific

What was supposed to happen

The story / requirement text the criteria came from

Report heading, e.g. the ticket key + name

Generate session report

Run Qiksy's a11y/markup audit on the current DOM (unlabeled controls, missing names, WCAG AA contrast, broken images, duplicate ids, positive tabindex, …) and return the findings. Also refreshes the panel. Static, non-destructive — reads the DOM only.

Run accessibility & markup audit

Everything about one recorded flow: its steps, every field with the value or placeholder it holds, and the flat label-to-value object the panel edits. Read this before running one you did not record — it is how you find out which placeholders exist and what a field is called.

The scenario name (or part of it) from qa_scenarios

Read one scenario in full

Replay a flow recorded in the panel, on the page as it is now, with YOUR data. Give `vars` for its placeholders ({ "summary": "Login 500s" }) and/or `values` to override any field by its label. This is how a form somebody fills weekly — a bug in Jira, a task, a story — becomes one call: the route was recorded once by a human who knows the form, and you supply the text. Each step is filled through the same engine as the panel's Fill, and the run STOPS at the first field the page no longer has rather than filling on and pressing Next over an invalid form. Requires Qiksy Pro and the one-time “Agent control” confirmation in the panel; without both the extension answers pro-required / consent-required and does nothing.

The scenario name from qa_scenarios

Override any field by its label — { "Priority": "High" }

Answers for the placeholders — { "summary": "…", "steps": "…" }

Run a scenario the human recorded (Pro)

Turn what you just drove into a scenario in Qiksy's Scenarios tab — the same list the human records into by hand, on the same machine. Call it with a name and it builds the flow from what this session actually filled: fields by accessible name, uploads, and the control you clicked to move on, folded into steps. Pass `steps` to write or correct one by hand. THIS IS THE ONE THE HUMAN CAN PRESS. qa_recipe_save writes a file for you to replay; this puts it in front of the person, with Run, Data and Random beside it, and it can be part of a project suite. Do it at the end of any flow that took more than a few calls, and tell them in one line that it is there — a scenario nobody knows about is one nobody runs. Needs Pro (scenarios are a Pro feature); it stores data and touches no page, so it needs no Agent-control consent.

Read the answers off the form AS IT STANDS on the page, instead of from what this session drove. This is the one to use when the HUMAN filled the form themselves and then asked you to save it — you were not there, so there is nothing in the journal to fold. ONE PAGE ONLY: a wizard's earlier screens are no longer in the DOM, so a multi-step flow has to be recorded with the panel's Record button instead, and the reply says so. Passwords are kept as fields, never as values.

What the human will look for in the list — "file a bug", "new client", "weekly invoice"

Anything the replay should know that the fields do not say — a precondition, a role to be signed in as

Which product or client this belongs to. It groups the list AND is what qa_suite_run runs by.

Write the steps explicitly instead of deriving them from this session

The field's accessible name — the durable key across runs, and what the panel shows the human

A password or card field: recorded as a FIELD, never as a value

Or a {placeholder}, which the human fills per run in the panel

Go to this address before the step — for a flow that crosses pages or domains

Target tab (from qa_tabs); omit for the active tab

Labels for picking a subset later — ["smoke"], ["billing"]

Where the flow starts. Defaults to the first step's page.

Save this flow into the panel, so the human can run it (Pro)

The flows the human recorded in Qiksy's Scenarios tab, on this machine: name, project, tags, step and field counts, and — the part you need — the PLACEHOLDERS each one asks for. A scenario stores its route, not its content: a bug report or a task keeps the same fields every time and different text, so the values are named holes ({summary}, {steps}) that you fill per run. Worth one call before any long form on a host the human works on. Free, no Pro, no browser action.

Only scenarios recorded on this host

Only scenarios filed under this project

List the scenarios recorded in the panel

A compact accessibility / interaction snapshot of the WHOLE page: every interactive control, landmark and heading with a role, an accessible name, its state, and a STABLE ref like [ref=e12]. Unlike qa_export — which lists only the FORM fields Qiksy detects and can miss inputs, file uploads, date pickers, selects and buttons — this "sees everything". Pass a ref straight back to qa_click / qa_type / qa_spotlight: a ref is unique and unambiguous, so it works where a CSS selector is duplicated across fields. Built in the live, already-authenticated page in ~milliseconds — no browser launch, no CDP. Re-run it after the page changes to refresh the refs. ONE SNAPSHOT OWNS ITS REFS: taking a new one RENUMBERS them, so every ref from an earlier snapshot is void even when its element is still on the page — e12 may now be a different control, and nothing will refuse the click. Keep only the refs of your latest snapshot; where you cannot, target by `name` (qa_click, qa_fill_json), which survives both a re-render and a renumbering. On a big app, NARROW IT: `fields_only` for the form controls, `roles` for exactly the kinds you want, `match` for a name, `within` for one dialog or step panel. Filtering happens on the way out and does NOT invalidate anything — the refs you get back work like any other. One step of a wizard usually needs `fields_only:true, roles:["button"]`, not the whole page.

Keep only form controls (inputs, textareas, selects, checkboxes, radios, comboboxes, sliders, file fields). The cheap view when you are filling a form; combine with roles:["button"] to keep Next/Submit too.

Default 'both'. 'tree' is the indented text only — about half the bytes, and enough when you just need refs and names; 'nodes' is the structured list only (each with its cssPath).

Add each node's box as "x,y,w,h" in CSS pixels — for overlap, clipping, off-screen and tap-target-size checks. Off by default: it is bulk on every node.

Cap the number of nodes returned

Keep only nodes whose accessible name contains this text (case-insensitive)

Keep only these roles, e.g. ["button","link"] or ["combobox"]. Unioned with fields_only when both are given.

Keep only the subtree under this selector — pass the `selector` of a container node from an earlier snapshot (a dialog, a step panel, a fieldset) to see just that step's controls

Full page snapshot (accessibility tree)

Visually highlight (dim + outline) an element on the page — target it by a qa_snapshot ref (preferred) or a CSS selector — so the human tester can see what the agent is referring to. A non-destructive overlay — it does not click, focus, or modify the element.

Optional caption shown on the highlight

A ref from qa_snapshot (e.g. "e12") — preferred over selector

CSS selector of the element to spotlight

Spotlight an element

Health snapshot of a page Qiksy is watching: URL, error/warning/form counts, and its isolated-login name if any. Defaults to the active tab; pass tabId (from qa_tabs) to target a specific tab.

QA status

Read and write the app's own localStorage / sessionStorage — flip a feature flag, expire a token to test the re-auth path, or prove what the app actually persisted after a save. Without `op` (or with op:'list'/'get') it READS and is free like every other read on this bridge; op:'set'|'remove'|'clear' WRITES and needs Pro + the Agent control consent, because changing a stored token or flag changes what the app does just as surely as clicking does. Closed vocabulary — it executes nothing you supply, it names a key. Listing truncates long values at 300 chars; ask for one key by name to get it whole.

Which store (default 'local')

The key to read, set or remove

Default 'list' (or 'get' when a key is given)

Target tab (from qa_tabs); omit for the active tab

The value, for op:'set'

Read or set the page's web storage

The COMPUTED styles of one element — colour, type, spacing, border, shadow, layout — plus its box in CSS pixels, and the CSS custom properties (design tokens) in scope for it. This is how you check a built page against a design: it answers "this button renders #3B82F6 at 15px with 22px padding" without a screenshot and without measuring anything by eye. Target it by a qa_snapshot ref (preferred) or a CSS selector. Read-only and executes NOTHING: the property list is fixed in the extension, so you name an element, never a program. Pair it with a design source (a Figma file, a token JSON) to report the diff, and with qa_spotlight to show the human which element you mean.

CSS selector of the element

Include the CSS custom properties in scope (default true)

Computed styles and box of an element

Replay a GROUP of saved flows back to back and answer about the whole set: which passed, which stopped, at what step and on what. Pick the set one of three ways — `recipes` by name, `project` (everything filed under that product or client), or `tag` (["smoke"]). BOTH STORES ARE IN THE SET: the flows you saved here and the ones the human recorded in the panel's Scenarios tab (qa_scenarios), so a hand-recorded flow can be part of a project run. A name held by both is run from the panel — that is the copy the person edits. Each recipe is opened at its own start URL first, so recipe two does not begin on recipe one's confirmation screen. It does NOT stop at the first failure — a set is only useful when you learn the state of all of it — but each recipe still stops at its own first unresolved step, because filling on through a broken flow is worse than a short report. START WITH dry_run:true: it resolves every step of every recipe, changes nothing, and needs neither Pro nor consent. That is the honest way to ask "do these still fit" before running them for real. IT ACTS: a suite multiplies what one recipe does, submits included. Requires Qiksy Pro and the one-time “Agent control” confirmation in the panel; without both the extension answers pro-required / consent-required and does nothing.

Resolve every step of every recipe and touch nothing. Read-only.

Run every recipe filed under this project

Recipe names, in the order you want them run

Run every recipe carrying this tag

Per-recipe value overrides, keyed by recipe name: { "new initiative": { "Initiative name": "Run 2" } }

Run several saved recipes as one set (Pro)

List the browser tabs Qiksy can read, including which are ISOLATED multi-login sessions (isolatedSession = the login name). Use a tab's tabId with the other tools to read that specific login.

QA tabs

Return a generated per-page exploratory-testing checklist (from detected forms + interactive surfaces), with items auto-checked from the recorded session. Great raw material for writing test cases. Returns markdown + structured items.

Exploratory tour / coverage checklist

Put a value into ONE control, whatever kind it is — target it by a qa_snapshot ref (preferred) or a CSS selector. This is not a keystroke emulator, it is the extension's own fill engine, the same one behind the ⚡Fill button, so "typing" works on far more than text boxes: text/number/date inputs and textareas (native value setter + InputEvent, so React/Vue controlled inputs keep the value), native <select> (your text is matched against the option labels), checkboxes and radios (a truthy value checks it, with a real click so the app's listeners run), CUSTOM SELECTS and typeahead comboboxes (Radix/shadcn, MUI, Ant, react-select, Downshift — it opens the popover, waits for the options, picks the one matching your value and verifies the trigger actually changed), POPUP DATE & TIME PICKERS (opens the calendar and picks a day), sliders, and contenteditable rich text. A file field takes the neutral Qiksy test file matched to its `accept` — use qa_upload when the bytes matter. So do NOT click a dropdown open, snapshot to read its options and click one: name the field and the value you want. Only fall back to the click path when this answers ok:false. Reports back whether the value stuck, so a masked or read-only field is visible to you rather than silently ignored. Requires Qiksy Pro and the one-time “Agent control” confirmation in the panel; without both the extension answers pro-required / consent-required and does nothing.

With `raw`: move focus away afterwards. Some controls keep a typed value only once focus LEAVES — a tags field is the usual one.

With `raw`: the key that commits the value, default "Enter". Pass an empty string for none.

The field's accessible name — resolved against a snapshot taken right now, so it survives the re-render that invalidates a ref. Use it for a field you are re-filling after something else changed.

With `raw`: click the control first. A select filters only while its list is open, so typing into a closed one leaves it empty while looking filled.

With `raw`: after writing the text, CLICK the option whose text matches it — the other half of the fast route for a select, because the text only filters and something still has to choose the row.

With `pick`: how long to wait for that option, default 1200. It returns the moment the option appears.

WRITE THE TEXT VERBATIM and pick nothing — the fast route through a composite widget. Every date, time, range, tags field and searchable select in Ant Design, MUI and react-datepicker has its own text input and takes the value in the format it DISPLAYS ("06/11/2024", "14:30", the option text); typing it costs under half a second where driving the popup costs 7 to 35 seconds (measured on a live stand). Use it when you already know the value. Leave it off when the widget itself is what you are testing: the default path opens the popover the way a user would, and converts a date-ish value to ISO, which is right for <input type=date> and wrong for a component whose format is DD/MM/YYYY.

A ref from qa_snapshot (e.g. "e12") — preferred over selector; unique where a selector is ambiguous

CSS selector of the field

With `raw`: the cap on waiting for an option before the commit key. A select fed by a request needs ~900; a date parses its own text and needs none.

Target tab (from qa_tabs); omit for the active tab

The value you want: text, an option label for a select or combobox, a truthy/falsy word for a checkbox, a number for a slider

Set a field to a value — any kind of field (Pro)

Fill an ENTIRE form (or one step of a wizard) in ONE call instead of a round-trip per field: pass an array of { ref | selector, value, action? }. EVERY control kind qa_type drives goes in the same batch — custom selects and typeahead comboboxes (Radix/shadcn, MUI, Ant, react-select), popup date & time pickers, native selects, checkboxes, radios, sliders, rich text, plain inputs. A batch of ten fields where six are dropdowns and dates is the NORMAL use of this tool, not an edge case, and it is the difference between one call and thirty. They are filled in order and strictly one at a time (two open popovers break each other), so a step with several custom widgets still takes a few seconds of real waiting — that part is the widgets, not the round trip. PREFER `ref` from qa_snapshot: a form built from a repeated component gives several inputs the identical cssPath, and a batch of selectors would then pour every value into the first match. Returns a per-field result list plus filled/total; a field that came back ok:false is the only one worth a follow-up call. File fields are the one thing that belongs elsewhere — qa_upload takes files[] and attaches several in one round trip. Requires Qiksy Pro and the one-time “Agent control” confirmation in the panel; without both the extension answers pro-required / consent-required and does nothing.

The fields to fill, in order — put the whole step in here

Default "type" — which already covers selects, comboboxes, pickers, checkboxes and radios. Use "click" only for a button or a link.

With `raw`: move focus away afterwards — a tags field keeps its value only once focus leaves.

With `raw`: the key that commits the value, default "Enter". Pass an empty string for a plain input, where Enter would submit the form.

With `raw`: click the control first. A select filters only while its list is open, so typing into a closed one leaves the field empty while looking filled.

With `raw`: after writing the text, CLICK the option whose text matches it. The other half of the fast route for a select — the text only filters, and something still has to choose the row.

With `pick`: how long to wait for that option, default 1200. It returns the moment the option appears, so a generous cap costs nothing.

WRITE THE TEXT VERBATIM into this field and pick nothing — the fast route. Every composite in Ant Design, MUI and react-datepicker has a text input that takes the value in the format it DISPLAYS ("06/11/2024", "14:30", the option text), and a raw write costs milliseconds where driving its popup costs seconds. Raw entries in a batch also go in ONE pass instead of one-by-one, because they open nothing that could collide.

A ref from qa_snapshot — REQUIRED when several fields share one cssPath, which is common on forms built from a repeated component

CSS selector of the field — use `ref` instead when the selector is not unique

With `raw`: how long to WAIT FOR AN OPTION before pressing the commit key — a cap, not a sleep. A select whose options arrive from a request needs ~900; a date parses its own text and needs none.

The value you want: text, an option label for a native OR custom select / combobox, a truthy word for a checkbox, a number for a slider. A date picker opens and picks for you.

Fill a whole step in one call — every kind of field (Pro)

Put a file into an <input type=file> — including the hidden ones behind a styled dropzone, which a click can never reach. Three ways to choose what goes in: `fixture` for a hostile edge-case file (the upload counterpart of naughty strings — empty, oversize, wrong-type, corrupt, unicode name, unsanitised SVG…), `path` for a file on this machine, or `content` as base64. Pass `content` as base64 to attach a file YOU generated (a PDF fixture, a malformed CSV, an oversized image); omit it and Qiksy attaches a neutral test file matched to the field's `accept`. A content script has no filesystem access and the OS file picker is a modal an agent must never open, so bytes over this bridge are the only way a file from outside the browser gets in. Delivery fires both paths uploaders use — assigning `input.files` + change, and a synthetic drop on the nearest dropzone — because react-dropzone-style components listen only for the second. SEVERAL FIELDS IN ONE CALL: pass `files` — an array of the same arguments — and they are attached in order, one round trip for the whole step instead of one per file.

Base64 file content, for a file you are holding in memory. Prefer `path`.

The upload CONTROL's accessible name — "Premises photos", "Company logo". Prefer this over a ref: an upload field is usually a hidden input behind a styled dropzone, and a step with two dropzones has two of them. Without a field (and without a ref or selector) the file lands in the page's FIRST file input, which is how two photos ended up attached to the logo.

Attach several files in ONE call — each entry takes the same arguments as a single upload. Use this when a step has more than one upload field.

Base64 file content

The upload CONTROL's accessible name — "Premises photos". Without it the file goes to the page's FIRST file input, which on a step with two dropzones is the wrong one.

A hostile fixture built in the page — see the single-file `fixture` above

image pdf csv empty oversize wrong-type corrupt long-name unicode-name svg-script double-ext

File name, e.g. 'report.pdf'

Absolute path to a file on this machine — this process reads it

A ref from qa_snapshot

CSS selector of the file input or its dropzone

A HOSTILE fixture built in the page, so it costs nothing to send: empty (0 bytes) · oversize (12MB) · wrong-type (a PNG named .pdf — is content checked or only the extension?) · corrupt (truncated PNG) · long-name (255 chars) · unicode-name (RTL + emoji + CJK) · svg-script (is an uploaded SVG sanitised?) · double-ext (invoice.pdf.exe — does the UI show the whole name?). The answer comes back as `asks`.

MIME type, e.g. 'application/pdf'

File name, e.g. 'report.pdf'

Absolute path to a file ON THIS MACHINE — the server reads and encodes it for you. Use this instead of `content` for anything bigger than a few hundred bytes.

A ref from qa_snapshot

CSS selector of the file input or its dropzone; omit to use the page's first file input

Target tab (from qa_tabs); omit for the active tab

Attach a file to an upload field (Pro)

Block until the tab has finished loading AND Qiksy is live in the new document. Call this after anything that navigates — a submit, a link click, qa_navigate — before the next qa_type/qa_click, or the call lands on a page that is still being replaced. Read-only: waiting is not acting, so this needs no Pro and no consent.

How long to wait, default 15000, max 60000

Wait for the page to be ready


Zendesk Help Center. Specify the operation and its parameters.

Available operations:
- **search_articles**: Full-text search across Help Center articles (metadata only, no body).
- **get_article**: Retrieve an article by ID with full body content.
- **list_categories**: List all Help Center categories.
- **list_sections**: List sections, optionally filtered by category ID and locale.
- **list_articles**: List articles (metadata only, no body).
- **list_article_translations**: List all available translations for an article (metadata only, no body: locale, title, draft, updated_at).
- **create_article_translation**: Create a translation for an existing article in a specific locale. (write)
- **update_article_translation**: Update article content (title, body) in a specific locale. (write)
- **list_permission_groups**: List all Guide permission groups.
- **create_article**: Create a new article in a section. (write)
- **update_article**: Update article metadata only (draft, promoted, labels, tags, visibility, section, etc.). (write)
- **list_content_tags**: List all Guide content tags.
- **create_content_tag**: Create a new content tag for Guide articles. (write)
- **list_labels**: List all article labels.
- **list_user_segments**: List all user segments.
- **list_article_attachments**: List all attachments for an article.
- **get_article_outline**: Return a compact outline of an article (list of sections delimited by h1/h2/h3, with word counts) for the given locale (defaults to source_locale).
- **get_article_section**: Retrieve the content of a single section of an article in a given locale.
- **update_article_section**: Replace the content of a single section of an article in a given locale, keeping the rest of the body intact. (write)
- **compare_translations**: Compare section structure between two locales of the same article, matched by index.
- **create_article_attachment**: Upload an attachment to an article. (write)

One of: search_articles, get_article, list_categories, list_sections, list_articles, list_article_translations, create_article_translation, update_article_translation, list_permission_groups, create_article, update_article, list_content_tags, create_content_tag, list_labels, list_user_segments, list_article_attachments, get_article_outline, get_article_section, update_article_section, compare_translations, create_article_attachment

Operation parameters

Zendesk Help Center

Zendesk Tickets. Specify the operation and its parameters.

Available operations:
- **get_ticket**: Retrieve a Zendesk ticket by ID, including its comments if requested.
- **get_ticket_attachments**: Retrieve ticket attachments.
- **search_tickets**: Search tickets using Zendesk query syntax (e.g., "status:open assignee:me", "priority:urgent type:incident").
- **create_ticket**: Create a new Zendesk support ticket with subject, description, and optional priority/type/assignee/tags. (write)
- **update_ticket**: Update an existing ticket (status, priority, type, assignee, group, subject, tags, custom fields). (write)
- **add_private_note**: Add an internal note (not visible to requester) to a ticket. (write)
- **add_public_comment**: Add a public comment (visible to requester) to a ticket. (write)
- **list_tickets**: List tickets with cursor-based pagination, sorted by most recently updated.
- **get_linked_incidents**: Get all incident tickets linked to a problem ticket.
- **manage_tags**: Add or remove tags on a ticket. (write)
- **search**: Search across tickets, users, and organizations.

One of: get_ticket, get_ticket_attachments, search_tickets, create_ticket, update_ticket, add_private_note, add_public_comment, list_tickets, get_linked_incidents, manage_tags, search

Operation parameters

Zendesk Tickets

Zendesk Users. Specify the operation and its parameters.

Available operations:
- **get_current_user**: Get the currently authenticated Zendesk user.
- **search_users**: Search for users by name, email, or other criteria using Zendesk search query syntax.
- **get_user**: Retrieve a user by ID.
- **get_organization**: Retrieve an organization by ID.
- **list_organizations**: List all organizations with pagination.

One of: get_current_user, search_users, get_user, get_organization, list_organizations

Operation parameters

Zendesk Users


Checkpoint Pastepile memory

Update an existing Pastepile memory while preserving its previous content in version history. Use this for conversation snapshots: after significant growth, a debugging breakthrough, an architecture decision, a large code generation, or before context compaction. With an API key configured, it can checkpoint any paste that same key created without the one-time edit_key. Otherwise pass the edit_key returned by pastepile_save. Reusing one slug avoids duplicate memories while keeping every prior checkpoint recoverable from the paste's version history.

The complete current memory to store. Required. The previous content becomes a version-history checkpoint.

Optional. The one-time edit key returned by pastepile_save. Only needed when the configured API key did not create this paste. When both credentials are available, the narrower edit key is used.

Optional syntax-highlighting language, e.g. "markdown", "typescript", or "python". Defaults to "markdown" for conversation memory.

The paste slug (e.g. "abc123") or full Pastepile URL to checkpoint. Required.

A short, stable title for this memory. Required so search keeps a strong signal across checkpoints.

Forget a Pastepile paste

Permanently delete a paste from Pastepile. Use this when the user asks you to forget, remove, or delete something you saved earlier. With an API key configured you can delete any paste that was saved with that key, WITHOUT the one-time edit_key, which is what makes saved memory reversible across sessions. A paste saved with no key (or by someone else) needs its edit_key passed explicitly. Deletion is immediate and permanent: there is no undo and no trash. Confirm with the user before forgetting anything they did not just ask you to forget.

Optional. The one-time edit key from the pastepile_save result. Only needed for a paste that the configured API key did not create, for example one saved with no key at all. When both credentials are available the edit key is the one used, because it authorizes this paste alone.

Alternative to `slug`: the session name a memory was saved under with pastepile_remember. Use this when the user asks to forget a memory by what it is about and the slug is no longer in the conversation. Required to clear a local demonstration memory, which has no slug because it was never uploaded.

The paste slug (e.g. "abc123") or a full share URL (e.g. "https://pastepile.com/p/abc123"). Required.

Get a Pastepile paste

Retrieve a previously saved paste or memory in full, by slug, full Pastepile URL, or the `session` a memory was saved under. Returns the title, language, and file contents. Use this after pastepile_recall when a preview is not enough. An ENCRYPTED MEMORY of your own is decrypted here on this machine with the key in your Pastepile state directory; if that key is missing or wrong this says so rather than returning ciphertext. Password-protected and burn-after-read pastes, and encrypted pastes belonging to someone else, are not retrievable through this tool.

The session name a memory was saved under with pastepile_remember. Use this when you no longer have the slug, which is the usual case after a long conversation. Give this or `slug`, not both.

The paste slug (e.g. "abc123") or a full share URL (e.g. "https://pastepile.com/p/abc123"). Give this or `session`.

List Pastepile pastes

List recent Pastepile pastes. With an API key configured this defaults to scope "mine": YOUR saved pastes, newest first, including unlisted ones. Use scope "public" for the public feed. For targeted lookups use pastepile_search instead.

Maximum results to return (1-100, default 20).

"mine" lists pastes saved with the configured API key (default when a key is set); "public" lists the public feed (default without a key).

Memory key: back up, verify, restore

Back up, check, and restore the key that opens your encrypted memories. Pastepile does not have this key and cannot reissue it, so a machine that loses it loses those memories permanently. Use `status` to see whether a key exists here, `backup` to write a copy to a path the user gives you, `verify` to confirm a backup file still matches, and `restore` to install a key on a new machine. NONE of these ever returns the key itself: it would land in this conversation and in whatever logs the conversation reaches. Tell the user the file path and let them move the file.

status: is there a key on this machine. backup: copy it to `path`. verify: does the key in `path` match the one here. restore: install the key from `path`.

The file to write to or read from. Required for backup, verify and restore. Ask the user where; do not invent a location, and do not choose somewhere that syncs to a service they did not name.

Only for restore, and only after the user has said yes. Replacing a different key that is already installed makes whatever it sealed unreadable, permanently and silently. Without this, restore refuses rather than doing that.

Recall memory

Search YOUR OWN memory (everything saved with the configured API key) by text, tag, and kind, newest and most relevant first. Use this at the start of a session when the user refers to earlier work, and before asking them to repeat context you may already be holding. Returns titles, previews, sessions and URLs, not full bodies; fetch one with pastepile_get when you need all of it. With an API key this searches that key's memory from any machine; without one it searches the trial memory this device saved.

Only memories of this kind.

conversation decision code research note log

Words to match against titles and contents. Quoted phrases and -exclusions work. Omit to list recent memory instead of searching.

Only memories carrying ALL of these tags.

Remember (create or update memory)

Save the current state of your work to durable memory, keyed by a session name YOU choose. This is the primary tool: prefer it over pastepile_save for anything you may want back later. The first call under a session creates the memory; every call after updates that same memory and keeps the previous content as a version; a call whose content is unchanged does nothing and costs nothing. You never need to track a slug, a URL, or an edit key between calls, and you must never ask the user for one. Send the WHOLE current memory each time, not a delta. Works without an API key as trial memory (expires a month after its last save, searchable from this device only); a Pro API key makes memory permanent and portable.

The complete memory as it stands now. It replaces the current content; the previous copy is preserved in version history.

Seal the content on this machine before sending it, so Pastepile stores ciphertext it cannot open. The key is generated once and kept in a file on this device; IF THAT FILE IS LOST THE MEMORY IS UNREADABLE FOREVER, because Pastepile does not hold a copy. Costs: full-text recall cannot search inside an encrypted memory (find it by session, tag or kind), no title or preview comes back from recall, and every save is a real checkpoint because two encryptions of the same text are not comparable, so do not autosave an encrypted session on a timer. Use it when the user asks for it or the material is plainly sensitive; do not turn it on by yourself for ordinary work.

What this memory IS, so recall can filter by it. Defaults to "conversation".

Syntax-highlighting language. Defaults to "markdown", which is usually right for conversation memory.

Optional named collection to file this memory into, created on first use, e.g. "architecture-decisions". Lets a set of related memories be opened and shared with one link.

A stable name for this thread of work that you can reproduce from what you can see right now, for example "acme-api/auth-refactor" or a repository path plus the task. Reuse it for every save about the same work; that is what makes this an update rather than a duplicate. 1 to 120 characters of letters, numbers, spaces and . _ : @ / # -

Up to 20 short labels for later retrieval, e.g. ["auth", "postgres"]. Lowercase letters, digits and single hyphens; other spellings are rejected rather than silently dropped.

A short, stable title. Keep it the same across saves of the same memory so the history reads as one thing changing. Defaults to the session name.

Restore a memory version

Put an earlier version of a memory back as the current one. This is not destructive: what is current now is preserved as a new version first, so a restore can itself be undone. Use it when a memory was overwritten with something worse, or to return to a known-good state after an experiment. Name the memory by `session` or by `slug`, exactly one. With the API key that wrote the memory, any listed version can come back; trial memory (no key) restores the previous save only.

The session name you passed to pastepile_remember. Prefer this: an undo is most often wanted long after the slug scrolled away.

The memory slug or its full Pastepile URL.

The version number to restore, as listed by pastepile_timeline.

Save to Pastepile

Save text, code, notes, or any knowledge to Pastepile and get back a stable, shareable URL you can retrieve later. Use this as durable memory: whenever you produce output worth keeping across sessions, save it and remember the returned slug or URL. Returns url, slug, raw_url, and edit_key. The edit_key is shown only once and is required to update with a per-paste credential. With an API key configured, pastepile_checkpoint updates a paste that same key saved using only its slug, while preserving the previous revision in history. Deleting is separate: pastepile_forget removes a paste saved with the configured API key using only its slug.

The text or code to store. Required.

When the paste expires. Defaults to "never" so stored knowledge persists. "burn" destroys it after the first read.

Optional syntax-highlighting language, e.g. "typescript", "python", "markdown". Defaults to "plaintext".

Optional memory namespace, e.g. "architecture-decisions" or "debugging-notes". Saves this paste into a named Pile that is created on first use and appended to every time after, so related context stays together and can be shared with one link. Requires an API key, since a namespace belongs to the key that writes to it. Lowercase letters, numbers, hyphens and underscores; 2 to 64 characters.

Optional short title for the paste.

"unlisted" (default) keeps the paste out of public listings and search but retrievable by URL. "public" also lists it and makes it findable via pastepile_search.

Search Pastepile

Search Pastepile pastes by keyword and get back matching titles, previews, and URLs. With an API key configured this defaults to scope "mine": YOUR private memory, the pastes saved with that key (titles, filenames, and contents, including unlisted pastes). Use scope "public" to search the global public corpus instead. Without a key only the public scope is available.

Keywords to match against paste titles and content. Required.

"mine" searches pastes saved with the configured API key (default when a key is set); "public" searches the public corpus (default without a key).

Memory timeline

Show one memory's full version history plus the memories most related to it. Each entry has a version number, a timestamp, a size and a preview, so you can see how the work changed without downloading every revision. Pass a version number to pastepile_restore to bring one back. Name the memory by `session` if you still know the session name you saved under, which you usually do, or by `slug` if you have it. Give exactly one. With an API key this reads that key's full server-side history; without one it reads this device's trial-memory timeline.

The session name you passed to pastepile_remember. Prefer this: it is the identifier you can reproduce after a long conversation, and the slug is not.

The memory slug (e.g. "abc123") or its full Pastepile URL, as returned by pastepile_remember or pastepile_recall.


Get results for a completed query. Returns error if query is still running.

Maximum number of rows to return (default: 1000)

The query execution ID

Get the current status of a query execution

The query execution ID

List all saved (named) Athena queries available in your AWS account.

Execute a SQL query using AWS Athena. Returns full results if query completes before timeout, otherwise returns queryExecutionId.

The Athena database to query

SQL query to execute

Timeout in milliseconds (default: 60000)

Execute a saved (named) Athena query by its query ID.

Optional database override

Athena NamedQueryId


Fetch the full lyrics of one song from lyrics.com, given the song id or URL returned by search_lyrics or search_songs. Lyrics can be long, so the response is truncated by default: check 'truncated' and call again with 'offset' set to 'next_offset' to continue reading. Some lyrics.com pages legitimately have no lyrics on file; those come back with status "no_lyrics" and an empty lyrics field, which is a valid answer and not an error, so do not retry them. Always cite 'source_url' and the artist when showing lyrics to a user.

Optional word. When set, the response reports whether it appears in the lyrics and on which line.

lyrics.com numeric song id, as returned by the search tools. Preferred over 'url'.

Maximum characters of lyrics text to return in this call.

Character offset to resume from, for lyrics longer than max_chars.

Full lyrics.com song URL. Only www.lyrics.com URLs are accepted. Ignored when 'id' is given.

Ready-to-display credit line.

Slice of the lyrics text. Empty when status is 'no_lyrics'.

status id title artist source_url lyrics total_chars returned_chars offset next_offset truncated line_count highlight attribution source notes

Get full lyrics

Search lyrics.com for songs whose lyrics contain a given word or phrase. Returns matching songs with artist, title, a short excerpt of the line where the word appears, and the lyrics.com id and URL needed to fetch the full text with get_lyrics. Use this when someone remembers a fragment of lyrics but not the song, or wants songs mentioning a word or theme. One call returns one page of lyrics.com results; to see more, increase 'page' rather than 'limit'. lyrics.com also returns loose and title-only matches, so results are filtered locally to keep only songs where the word genuinely appears in the lyrics. Set 'verify' to "none" to see the raw, unfiltered list.

Include the matching lyric line excerpt in each result.

Maximum songs to return from this page.

Result page on lyrics.com. Each page holds up to 24 raw results.

Word or short phrase to look for inside the lyrics, for example 'autrefois'.

How to confirm the query really appears in the lyrics. 'snippet' checks the excerpt lyrics.com already returned and costs nothing. 'full' fetches up to 5 song pages and checks the complete lyrics, which is slow and can trigger rate limiting. 'none' disables filtering.

Rows dropped because the query was not found in their lyrics.

Caveats worth knowing, such as a cache hit or partial verification.

Rows lyrics.com returned before local filtering and deduplication.

Short lyric line showing where the query appears, when available.

lyrics.com song id. Pass this to get_lyrics.

Canonical lyrics.com page for this song.

id title artist album year source_url excerpt

Search lyrics by word

Find songs on lyrics.com by their title. Returns candidate songs with artist, album, year, and the lyrics.com id and URL. Use this when someone names a song and you need its id to call get_lyrics, or to tell covers and versions by different artists apart. An optional 'artist' narrows the list. lyrics.com searches titles and lyrics together, so results are ranked and filtered locally by title match; use match="strict" to keep only genuine title matches.

Optional artist name, matched case-insensitively against each result.

'strict' keeps only results whose title matches the query as a whole title, ignoring suffixes such as '(Remastered)'. 'loose' keeps anything lyrics.com returned, best match first.

Song title, or part of it.

Search songs by title


使用 SenseNova U1 Fast 模型，根据文本描述生成图像。支持中文 prompt，返回临时 URL 请及时下载。

生成数量，1~4 张。

图像描述文本，支持中文。描述越详细（构图、色彩、风格、元素）效果越好。最大约 4096 token。

图像分辨率，支持 11 种尺寸。默认 2752x1536(16:9)。


Read one or multiple Facebook Group posts and their comments through the user's authenticated browser session. Pass a 'posts' array to read multiple posts, or pass single-post parameters (groupId + url/postId) directly.

Per-call override: set true for background or false for foreground testing. Omit to use the extension default.

Single-post parameter: Target Group ID.

Single-post parameter: Stable local id returned by search.

List of posts to read (up to 20 posts per call).

Stable local id returned by search.

Canonical post URL.

Single-post parameter: Required only when resolving postId without a URL.

Single-post parameter: Search-result text.

Single-post parameter: Canonical Group post URL.

STEP 2: Search for posts matching a keyword inside one or more Facebook Groups. You MUST call facebook_list_groups first to get groupIds, then pass those groupIds and your search query here.

List of group IDs (1 to 10) from facebook_list_groups to search within.

The search keyword, topic, or question to search inside group posts.

STEP 1 (Mandatory first step): List all Facebook Groups available in the user's browser session. Returns group IDs and names. Call this tool first WITHOUT query keywords to discover group IDs before searching for posts.

Optional: force re-sync the group list from the Facebook browser session.


Your subscription: the entitlement tier and account cap, the provider's finer status, the current period end, and the price. Answers cleanly even when billing is switched off. GET /v1/billing/status.

Billing status

Exchanges what the human pasted from the browser for a linked account, using the link_session_id from start_account_link. Pass it verbatim — for some providers that is a code, for others the whole redirect URL, and the provider parses either. A mistyped value is rejected without spending the session — retry until it expires. Needs a key holding manage, the same as start_account_link. POST /v1/accounts/link/complete.

Exactly what the human copied, verbatim — a code, or a whole redirect URL, depending on the provider. Do not trim it to what you expect.

The link_session_id returned by start_account_link.

Complete linking an account

Creates an EMPTY pool and returns its id. A pool is a named subset of the linked accounts; a key bound to one routes only inside it, so one project cannot spend the quota set aside for another.

It has NO ACCOUNTS until you call `set_pool_accounts`, and a key bound to an empty pool can serve nothing at all — so fill it before you mint against it. Requires a key holding `manage`. POST /v1/pools.

A label for the pool, unique per tenant.

Create a pool

Removes a pool. IRREVERSIBLE — the name and the membership then exist nowhere, and the accounts themselves are untouched.

Refused with 409 while an unrevoked key is still bound to it, because deleting would WIDEN that key from one pool to every account — the one direction this must never move on its own. Revoke or rebind the key first. Requires `manage`. DELETE /v1/pools/{id}.

The pool id, from `list_pools`.

Delete a pool

How much of every linked account's subscription is spent right now and when each window resets — the answer to 'how much have I got left?'. Every account is listed, tightest window first, with the one that still has the most headroom named. `utilization` is a fraction in [0, 1] (0.29 is 29% spent). `resets_at` is an absolute instant, or null when the provider publishes no rollover for that window: the utilization is still a measurement and routing still acts on it, but nothing can say when it comes back, and a line that reads 'when it resets is not reported' means exactly that and not that the window is stale. `window` is an opaque provider label (`5h`, `7d`, `primary`, and others): read it as data and expect labels you have not seen. An account with an empty `limits` is not zero spent — the line says which kind of empty it is: a provider with no quota to meter, one whose reading arrives when the account serves a request, or one that is asked for its usage on a schedule instead. Use this to pick which account to route work through. GET /v1/limits.

Subscription limits across the pool

One-glance health of the megaloop pool: the endpoint in use, the billing plan, how many linked accounts are active vs cooling_down vs paused, and how much of each account's subscription is spent — per window, with the reset instant, plus which account still has the most headroom. Answers 'how much have I got left?' in one call. Composes GET /v1/accounts with GET /v1/billing/status.

Megaloop status

The most recent request events, newest first: model, account, response_class (the rotation verdict — a pause_account or try_another_account is an account dropping out), status code and latency. GET /v1/requests.

PAGING: send `before` AND `before_id` together, both taken from the last row of the previous page. `before` alone loses rows that share its millisecond — and it still returns 200, so a walk that omits `before_id` silently reports a short answer.

ISO-8601 keyset cursor: return only events created strictly before it. Take it from the LAST row of the previous page, and send `before_id` with it — see there.

The id of that same last row. NOT OPTIONAL IN PRACTICE when paging: `before` alone skips every row sharing its millisecond, and parallel requests land inside one millisecond routinely, so a walk without this LOSES ROWS. It still returns 200 and still returns rows, which is what makes it easy to miss.

How many events (default 50, max 200).

Return only the requests that did not serve. Applied by the server as `response_class <> 'ok'` over the whole retained history, so it finds failures that are not on the page you would otherwise have fetched.

ISO-8601 instant. Only events at or after it — the way to bound a question to the last hour or the last day without paging backwards through everything.

Recent request log

Per-account, per-day usage over a window: request count, error count, and summed input/output tokens. Omit from/to for the last seven days. GET /v1/usage.

ISO-8601 start of the window (inclusive).

How to bucket the same window. `account` (the default) is per subscription. `key` is ONE BUCKET PER APP — the only way to answer 'which of my apps is costing the most', since a key is what an app holds. `pool` is where the load went, and carries no token or cost fields because pricing needs the model.

ISO-8601 end of the window (exclusive).

Usage rollup

help

Start here. Says what megaloop is, maps each question an agent might have to the tool that answers it, and sets out what this key can do, what no key can do, and the rules for spending and for handling the key. Takes no arguments, calls no network and needs no valid key, so it answers when everything else is misconfigured.

What megaloop is and which tool to reach for

Every linked account with its health: status (active | cooling_down | paused), the reason it dropped out, cooldown_until, and last_used — plus `limits`, how much of that account's subscription is spent per window. This is how an account is seen to drop out of the pool. For headroom alone, get_limits is the narrower read. GET /v1/accounts.

List linked accounts

Your tenant's API keys, revoked ones included, with what each one is allowed to do. Only prefixes are shown — full key values are never returned. A key bound to a pool sees only the keys in that pool, including its own row; a session and an unbound key see all of them — so this is not necessarily the tenant's full inventory. GET /v1/keys.

List API keys

Your tenant's pools. A pool is a named subset of the linked accounts; a key bound to one routes only inside it, so one project cannot spend the subscription quota set aside for another. Pools are optional — a tenant with none simply has every key reaching every account, which is the default. Use the ids here with mint_key's pool_id. GET /v1/pools.

List pools

The providers you can link and the credential archetype each uses (oauth | api_key | endpoint). Use the returned `id` as the `provider` argument to start_account_link. An api_key or endpoint provider has no tool here — that link names a base URL, so it takes a signed-in person; ask the human to add it in the dashboard. `quota` says whether the provider meters a subscription window at all, and `paste_prompt` carries that provider's own wording for its paste step. GET /v1/providers.

List linkable providers

Creates a new sk-ml-v1- API key for your tenant. Store it where the customer keeps secrets before you go on — this result is the only place an AGENT can read it, and no later tool call returns it. The customer can show it again from the Keys page while signed in; no API key can, however powerful, so one leaked key cannot collect the rest. Never print it into a transcript or write it into a file that gets committed. Say nothing about capabilities and the new key serves inference and nothing else, which is what a client config needs. Say nothing about pool_id and the key reaches every linked account, unless this server's own key is limited to a pool, in which case the new key inherits that same pool. This server's own key must hold manage to call this at all, and may only pass on what it holds — the refusal says what to do if it cannot. POST /v1/keys.

What the new key may do. `read` sees the account (accounts, usage, traffic, limits, keys, plan); `inference` serves requests through the pool, spends the subscription quota and picks which account they land on; `manage` links accounts and mints or revokes keys. Omit it for the safe default, ["inference"], which is the right key for a client config. A key that only watches is ["read"]; the one this server usually wants is ["read","inference"]. Ask before including "manage": it links accounts and can mint replacements for itself, so revoking a leaked one does not undo the leak.

A label for the key, e.g. 'laptop' or 'ci'.

Limit the new key to one pool, by id from list_pools. A pool is a named subset of the linked accounts, so a key bound to one routes only inside it and cannot spend the quota set aside for another project. Omit it for every account, which is the default — but note that if THIS server's key is itself limited to a pool, omitting it inherits that pool rather than widening, and naming a different pool is refused.

Mint an API key

Changes a pool's label. Nothing routes on the name, so this changes no behaviour — keys stay bound and membership is untouched. Requires a key holding `manage`. PATCH /v1/pools/{id}.

The new label, unique per tenant.

The pool id, from `list_pools`.

Rename a pool

Revokes a key. Management calls stop the moment this returns; inference can keep accepting it for up to 60 seconds, because the gateway caches an accepted key for that long in a separate process — treat 60s as the window when rotating a credential you believe is compromised. Irreversible. Revoking the key this session authenticates with is refused unless you also pass confirm_self_revoke, because it ends the session and nothing in the resulting 401 explains why. That check reads GET /v1/keys, so it needs this server's key to hold `read` as well as `manage`; without it the revoke is refused rather than performed blind. DELETE /v1/keys/:id.

Only needed to revoke the key THIS session is using, which ends the session. Refused without it. Also what to pass when this server's key cannot read the key list, since the check cannot run then either.

The key id from list_keys.

Revoke an API key

REPLACES a pool's membership with exactly the accounts you name — it is not an add. To add one account, send the ids already in the pool plus the new one; `list_pools` returns the current set.

An account may be in several pools at once. Requires a key holding `manage`. PUT /v1/pools/{id}/accounts.

The complete membership the pool should end up with, by account id from `list_accounts`. Everything not named is removed.

The pool id, from `list_pools` or `create_pool`.

Set which accounts are in a pool

Begins the browser link flow for an oauth provider and returns an authorize URL. Open it, approve, then pass what the provider hands back to complete_account_link with the returned link_session_id. What it hands back differs per provider — one shows a code on a page, another redirects to a URL that must be copied whole — so the instructions in this tool's answer come from the provider itself; relay those rather than assuming a shape. The session expires in ten minutes. This server's own key must hold manage to call this — linking decides which upstreams serve the pool — and the refusal says what to do if it cannot. POST /v1/accounts/link/start.

Optional provider-defined variant; omit for default.

A label for this account, unique per provider for you.

Provider id from list_providers, e.g. an oauth provider.

Start linking an account (browser)


Explains what cogDepot is, what it costs, and where its machine-readable contracts live. cogDepot is a broker where autonomous agents publish capability listings, negotiate terms anonymously, and form direct peer-to-peer deals; the broker exits after the introduction. Requires no API key and spends no credits. Returns the platform description, the current credit prices, the anonymity and reputation rules, and the discovery URLs (agent card, OpenAPI). Prices are read from the live API on each call, so they are current rather than baked into this package. Call this first when asked what cogDepot is, what it charges, or whether it fits a task. Do NOT call it repeatedly - the answer only changes when cogDepot changes its pricing.

What cogDepot is and what it costs

Returns the complete public transaction record for one cogDepot agent, identified by its 12-character hex handle - the value shown as poster_id on every listing. Requires no API key, no account, and spends no credits. The record is ROLE-SPLIT: an agent's behaviour as a seller and as a buyer are tracked separately and never pooled, so read the facet matching the role it would play in your deal. Each facet carries warm_start. cogDepot seeds every new account with one synthetic 5-star rating per role, so an agent that has never traded reads as a flawless 5.0 over one rating; warm_start true means that rating was NEVER EARNED and no deal has sealed in that role. Do not present a warm-start facet as a track record. finalized_count is the unfakeable number: it is never seeded, and each one cost both sides a real fee. cogDepot attests only to deals it settled, and a rating moves only when at least one side was funded with real money - so these counters cannot be inflated by trading with yourself for free. Call it before committing to a counterparty, or to check your own standing as others see it.

The agent's 12-character hex handle, as shown in a listing's poster_id (for example a3f19c02b7e4).

Read an agent's cogDepot reputation record

Explains, in order, how to obtain a cogDepot API key and become able to trade. Requires no API key and spends no credits: this is the tool to call when the user has no cogDepot account yet, or when another tool has reported a missing or unfunded key. Covers all three ways a key is issued and how each one is funded, including the free domain-verification grant. Returns instructions for a human or agent to follow. It does NOT create an account and does not send any request on the user's behalf.

How to get a cogDepot account

Returns a sample of the capability listings currently live on cogDepot: what each one offers or wants, its category, and its asking price. Requires no API key and spends no credits. This is a PREVIEW, not the feed: up to 20 listings, no cursor, no filter and no search. Call it to show what is actually trading, or to judge whether cogDepot is worth an account before getting a key. Do NOT conclude from an empty or short result that no matching listing exists - this is a capped sample, not a search.

Preview live cogDepot listings


Read Airwallex integration best practices

CODE GENERATION ONLY: This tool MUST be called before any other Airwallex tools, but ONLY when the user intent is to generate code. For documentation searches, general questions, or non-code-related tasks, skip this tool and proceed directly with the appropriate tools for the task at hand.

SINGLE USE PER CONVERSATION: You MUST call this tool only ONCE per conversation. The best practices content is static and doesn't need to be re-read multiple times.

This tool reads the Airwallex integration best practices documentation that contains essential guidelines for API usage, payment handling, SDK implementation, and common pitfalls to avoid.

Search Airwallex Product, API & SDK documentation

Retrieve relevant sections from the official Airwallex documentation matching the user's question.

USAGE STRATEGY:
  DO: Prefer to start with a broad search without specifying any source and then narrow down the search with a specific source when needed
  DO: For relevant API endpoints or SDK methods in the sections returned, invoke this tool again with the specific source to get more detailed information
  DO: For API endpoints referenced, always remember to explicitly check how to perform API authentication
  DO: For SDK methods referenced, always remember to explicitly check how to initialize the SDK

PRIVACY & SECURITY REQUIREMENTS:
• DON'T: Include PII (Personally Identifiable Information) in questions
• DON'T: Include account IDs, user IDs, email addresses, or customer data
• DON'T: Include API keys, tokens, or credentials
• DON'T: Include transaction IDs, payment references, or financial data
• DO: Use generic examples like 'how to process payments' instead of specific account details
• DO: Focus on technical concepts, API endpoints, and implementation patterns
• DO: API version information is permitted as an exception (e.g., '2023-09-30')

The question to search the documentation with.

Documentation source to search. OMIT this parameter to search all sources. PREFER to start with a broad search and then narrow down the search with a specific source if needed. Set the source to `product-docs` for information related to integration or migration guides, general product enquiries & detailed API response error code descriptions and reasons. Set the source to `api-docs` for information related to specific API endpoints and for general API-related information related to versioning, authentication, rate limits, etc. Set the source to `js-sdk-docs` for specific information related to Airwallex.js or the Components SDK. For the legacy JS libraries, use `product-docs`, `ios-sdk-docs` for specific information related to the Payments iOS SDK, `android-sdk-docs` for specific information related to the Payments Android SDK.

product-docs api-docs js-sdk-docs ios-sdk-docs android-sdk-docs