For the complete documentation index, see llms.txt. This page is also available as Markdown.

MCP <> Connecting Your Clients' AI Assistants

How to host the AI authorization screen on your own site, with the Ask Clio CoPilot running as an iframe. Your customer approves the connection without leaving your page and without being sent to a Clio-hosted screen.

What you are building

When one of your customers connects an AI tool (Claude, ChatGPT) to their account, that tool starts an OAuth authorization. Clio needs a page to show the customer what is being requested so they can approve or deny it.

That page is yours. Clio redirects the browser to a route on your site; you already know who is signed in, so nobody has to authenticate again. You render the CoPilot in an iframe, it shows the consent card, and it hands the result back to the AI tool.

Before you start

Everything here is configured in the Ask Clio dashboard, under MCP Settings — available to anyone with a Firm Admin or Firm Employee role. Three fields matter:

  • Consent page URL — set this to your consent route. While it is empty, Clio sends your customers to a hosted fallback page that only your staff can complete. Include the trailing slash before any query string.

  • Allow client self-service — must be on, or the CoPilot tells your customers that connecting isn't available.

  • MCP enabled — the firm-level switch. Turning it off later revokes every live connection, not just new ones.

The same page shows your firm's connector URL, which is what your customers paste into their AI tool.

No tokens in that field

Consent page URL holds a plain route and nothing else — https://yourapp.com/ai-consent. It is a single static value for your whole firm, so a session token cannot go in it: tokens are per-customer and expire. Nor does client_id belong there.

Both are resolved inside your route, per request, at step 3 and step 4 below. That is where the flow becomes customer-specific — not in this setting. You never generate or send a consent link yourself; Clio sends each customer to this one route and your route works out who they are.

The flow

  1. AI tool → Clio

    The customer starts a connection

    They add your MCP server URL in Claude or ChatGPT. That tool calls Clio's /o/authorize, which validates the request and creates a short-lived authorization record.

  2. Clio → your site

    Clio redirects the browser to your route

    A top-level navigation to your consent_page_url with one parameter appended:

    Nobody generates that id by hand — not you, and not the AI tool. Clio creates the authorization record and appends its id on the way out, so it arrives on your route automatically.

    What is not automatic is getting it into the iframe. It lands on your page's URL; the embedded CoPilot reads its own frame URL, which is a different thing. Forwarding it inward is step 4, and it is the step most integrations miss.

  3. Your backend

    Identify the customer and mint a session token

    Authenticate them however you normally do. Then create an Ask Clio SDK session server-side — the same call you already make to embed the chat widget — and keep the returned token for the next step.

    Mint it per request

    Session tokens are per-customer and expire. Never hard-code one into consent_page_url or a static template; generate a fresh token each time this route is served.

  4. Your page

    Embed the CoPilot, carrying the request id

    The iframe URL needs three parameters: your client_id, the st session token from step 3, and the authorization_request_id from step 2. Whenever that third parameter is present, the CoPilot opens on the consent card instead of the chat.

    If you use the Ask Clio embed script rather than a raw iframe, append the same parameter to the URL you pass it and make sure the panel is open — a consent card behind a collapsed launcher looks like a dead end:

    Do not sandbox the frame

    Step 6 requires the frame to navigate the top-level page. If you must set sandbox, it has to include allow-top-navigation-by-user-activation alongside allow-scripts, allow-same-origin and allow-forms — or you must implement the message listener in step 6 instead.

  5. Your customer

    They approve or deny

    The CoPilot shows which AI tool is asking, whether the access is read-only or read & write, and every tool the connection grants. Their decision goes straight to Clio, authenticated with the session token — your page never handles any credential.

  6. Back to the AI tool

    The browser returns to the AI tool

    Clio replies with a redirect URL carrying the authorization code. This has to be a top-level navigation: pointing the iframe at claude.ai would try to load Claude inside your widget, and it refuses to be framed.

    The CoPilot navigates the top window for you, so an ordinary unsandboxed iframe needs no code here. If your page blocks top-level navigation, listen for the message instead and perform the redirect yourself:

    Always follow the redirect

    Send the customer to redirectTo even when it carries an error= parameter. A denial is a valid OAuth outcome and the AI tool knows how to present it. Check event.origin before acting on any message.

Constraints worth designing around

  • The request expires. An authorization request is valid for about ten minutes and can be used once. If your route bounces the customer through a login, they may return to an expired request — the CoPilot says so and asks them to start again from their AI tool.

  • One consent URL per firm. consent_page_url is a single value, so it must point at a route that works for every one of your customers rather than at anything user-specific.

  • Account details must be linked first. If your tools need values like a clearing account id and the customer's session does not carry them, the CoPilot refuses to connect rather than creating a connection that authenticates and then fails on every request.

  • Allow clipboard access. Without allow="clipboard-write" on the frame, copy buttons fall back to a legacy method that works but is less reliable.

If something goes wrong

What you see
Likely cause

The chat loads instead of the consent card

authorization_request_id never reached the iframe. Check the frame's src, not your page's URL.

Nothing visible; launcher stays collapsed

The panel was not opened. Call the SDK's open method when the parameter is present.

“This authorization request isn't valid”

The id is unknown or belongs to another firm — usually a truncated or re-used parameter.

“This request has expired or was already used”

Past the ten-minute window, or the customer double-submitted. They start again from the AI tool.

Approve succeeds, then a blank or refused panel

Top-level navigation was blocked. Implement the CLIO_CONSENT_COMPLETE listener.

“Connecting isn't available here yet”

Client self-service is off for your firm. Ask your Clio contact to enable it.

“Sign in through your firm to connect”

No st parameter, or the session expired. Mint a fresh token when serving the route.

The simpler alternative

If rendering consent inside your page is not a requirement, you can skip the embed entirely. Have your route mint the session token and then redirect top-level to the CoPilot:

The consent card fills the page, and the return trip needs no cooperation from you at all. Worth noting that either way the customer ends up at the AI tool when they approve — the only difference is whether the card renders inside your site for those few seconds.

Let your clients use their own AI assistant — Claude, ChatGPT, Perplexity, or any MCP-compatible client — to ask about their account in plain language. The assistant reaches your tools through Ask Clio and answers with live data.

You stay in control of which tools are reachable and whether any of them can act rather than only read. Your clients never leave your brand, and their credentials never reach the AI provider.

How It Works

Your firm already exposes tools to Ask Clio. This publishes a subset of them at a connector URL your clients paste into their AI client:

Find yours under Configuration → MCP, alongside the switch that turns the connector on. It carries your firm's name rather than ours, which is what lets your clients recognise it as yours; there is a second address that works too. If you do not see that section yet, your Ask Clio contact can give you the URL and flip the switch for you.

Your knowledge base comes along with the tools, with nothing to configure. Whatever you have published — documents, articles, URLs — is reachable through the connector the same way your own chat already answers from it, and stays current as you add to it.

Two things decide whether the assistant ever looks at a document. Titles reach the model without it searching, so 2025 fee schedule earns a look and document final v3 does not. Summaries are what it reads to decide whether to open one, before it has seen a word of the body. Neither is cosmetic here in the way it is on a shelf.


Choose a connection method

Three methods, and you can use any of them without the others. They all produce the same connection underneath, so Chat History, archiving and your audit trail look identical regardless.

Access Key
OAuth 2.1
In-app

What your client does

Pastes a key you show them

Pastes your connector URL, clicks approve

Connects from a panel in your product

What you build

One backend call

A consent page plus one backend endpoint

A panel, and no backend at all

Key handling

Shown once, copy-pasted

Never shown to anyone

Never shown to anyone

Best for

Getting started quickly

Production client experience

Clients already using your assistant

Most firms end up on OAuth, because a key someone has to copy is a key someone will paste into the wrong window.

The next four steps cover OAuth with a consent page you host yourself. That is the arrangement that keeps your clients' identity entirely on your side — Ask Clio never sees their browser. Connecting from inside your app comes after them, and composes with either of the other two rather than replacing them.


Under Configuration → MCP, set your consent page URL:

Leave it blank and your clients land on an Ask Clio-hosted page, which only your own staff can complete.

While you are there, copy your connector URL. Your clients need it.


When a client adds your connector, their AI assistant sends their browser to:

Your page authenticates them the way every other page of yours does. They are already signed in to your application, so you already know who they are.

Then fetch what they are being asked to approve:

No credentials needed — the id is itself proof of possession.

Render client_name and the tools list. Use display_name, not name — alpaca_list_open_positions_for_account is not something anyone can meaningfully consent to. Show access too, so read-only and read-write look different.

If expired or consumed is true, the request is spent. Tell your client to start again from their AI client. These live ten minutes by design.


Step 3 — Approve from your backend

When your client clicks approve, your page calls your own backend, which calls us:

client_id and client_secret are the Client Identity and Client Signing Key your firm already uses for the chat SDK. If you are creating session tokens today, you have them.

Your client_secret must never reach a browser. It mints connections for any of your users, so a page holding it hands that power to whoever opens the tab. This call belongs in your backend.

user.id is your own identifier for that person — the same value you already send when creating a session token for the chat SDK. We key their connection on it, so the same id always resolves to the same connection.


Step 4 — Send them back

The response gives you a URL:

Redirect the browser there. Their AI client finishes the handshake on its own, and the connector is live.


Your connector's own address

Your connector answers on two addresses, and they are the same server:

The second exists so your clients see your firm's name rather than ours when they add the connector, which is what "become your own app" comes down to in practice. There is nothing to configure and nothing to migrate. Both are live for you at the same time, and you choose which one you hand out.

You can change your mind later at no cost. A token issued on one address is accepted on the other, so a client already connected on the first URL keeps working: no reconnecting, no approving anything again, no window in which their assistant stops answering.

One thing does not move on its own, and it is worth telling clients. Whoever already pasted the old URL into their assistant keeps seeing that URL in their connector list, because that text lives in their client and we cannot rewrite it from here. Only connections made after the switch show the new address.

If you inspect discovery you will see the authorization server stays on mcp.askclio.ai under both addresses. That is deliberate rather than an oversight: your subdomain is the protected resource and ours is the authorization server, which is exactly the split RFC 9728 exists for. It means one place issues and revokes tokens for every firm, and your clients never see the difference.


Connecting from inside your app

Everything above assumes your client is somewhere else — in Claude, or on a page you sent them to. If they are already in your product with your embedded assistant open, none of that is necessary. They hold a session token you issued, we can verify it, and that is enough to let them set up their own connection without leaving the screen.

Your clients can approve a consent from here without you turning anything on. The Allow client self-service switch under Configuration → MCP governs one thing: whether they may generate and rotate their own access keys. It ships off, because handing your customers their own credentials is not something switching your connector on should imply, and if you want to stop them connecting altogether that is the master MCP switch rather than this one.

These endpoints live on the Ask Clio API host, not on the connector host the rest of this page uses — api.askclio.ai in production, dev-dashboard.askclio.ai in the sandbox. Every one of them authenticates with the session token your assistant already has:

Endpoint
What it is for

GET /api/sdk/mcp/status/

Everything the panel renders, in one call

POST /api/sdk/mcp/personal-keys/

Their key, rotating on each call

GET /api/sdk/mcp/connections/

What they have connected

POST /api/sdk/mcp/connections/<id>/revoke/

Disconnect one

POST /api/sdk/mcp/consent/<id>/approve/

Decide a consent in place

Two things this panel should not draw. A key that has been revoked is left out of status and connections here, unlike on the dashboard, which keeps them for audit; disconnecting revokes a connection's keys along with it, so after a disconnect expect no keys back and offer to generate one rather than showing the old value. And an OAuth connection has no key of its own, so access_keys comes back empty on those: show the connection, not an access key.

Do not ask them for their account details on this path. Step 2 exists because a hosted page has no idea who is standing in front of it. Here we do: the account context comes from their session, and anything you send in the request body is ignored rather than trusted — the caller is the client themselves, and honouring it would let one of them bind a connection to somebody else's account.

status returns required_context alongside context_ready, so your panel can tell whether anything is still missing instead of rendering a field nobody needs to fill in.

Connections made this way are read-only. Every other gate asks your firm before granting write, and on this path there would be nobody to ask.

To decide OAuth consents in-app as well, point your consent page URL at a route inside your product rather than at a standalone page. We append authorization_request_id to whatever URL you set, exactly as in Step 2, and your route posts the decision to the endpoint above with the session token instead of going through your backend.


Dynamic Inputs, under a different name

runtime_context is the same thing as Dynamic Inputs in the chat SDK, where the field is called tools_input. Same keys, same values, same purpose: injected into tool calls server-side, never shown to the model.

If you already pass tools_input when creating a session token, pass those same key-value pairs here. On the in-app path you do not pass them at all — they are already on the session.

This is the one that costs a day. If we do not have the account context, the connection still succeeds. It authenticates, it lists every tool, and then every single call fails — the unresolved field goes to your clearing house as a literal {{account_id}} and they answer about the account rather than about the missing context. It reads like a broken integration on their side. It is not.

Read required_context from Step 2 and use its key values verbatim.

The context key is not necessarily the parameter name your tools show. A firm whose tools take an input called account_id may still key its context on alpaca_account_id. Send what required_context says, not what looks right.

An empty required_context means your tools need nothing, and you can omit runtime_context.


Handling errors

Response
Meaning
What to do

404 on the GET

Unknown request id

Ask them to start again from their AI client

410 on approve

Already used, or expired

Same — single-use, ten-minute life

200 with error= in redirect_to

Rejected upstream

Redirect anyway; their AI client shows the error

400 {"firm": ...}

Your MCP connector is switched off

Turn it back on under Configuration → MCP

400 {"access": ...}

Read-write requested without it being enabled

Enable it, or request read-only

401 on an in-app call

No session token, or the session expired

Issue a fresh session token

429 on a tool call

The connection passed its per-minute limit

Back off and retry; ask us to raise the limit if it is routinely hit

Approve answers 200 whenever it reached a decision, even if the grant failed upstream. Check redirect_to for an error= parameter rather than relying on the status code.


Listing your connector as your own app

Everything above gets your clients connected by pasting a URL. Listing is the other route: your firm appears in Claude's connector directory and ChatGPT's app directory under your own name, and your clients find you there instead of being handed a link.

You submit, not us. The connector is yours, the API behind it is yours, and both reviews ask the owner to prove it. What we do is make sure nothing on our side stops you passing.

What we already provide

Your connector is served from your own subdomain, https://your-slug.mcp.askclio.ai/mcp, which matters more than it looks: OpenAI verifies domain ownership by asking that exact domain to hand back a token, so a shared address could only ever have verified one firm.

Every tool we publish carries a readable title and a flag saying whether it only reads or can change something. Anthropic's portal groups tools by exactly that and flags any that are missing it, so this is the difference between reaching review and being stopped before it.

Authentication is OAuth 2.1 with dynamic client registration, which is what both directories expect, and the connection is HTTPS throughout.

Claude

Submit from the directory submission portal inside your own Claude organisation's settings. You need a Team or Enterprise organisation, since the settings do not exist on individual plans, and by default only Owners can submit.

The portal connects to your live connector and syncs your tools, so have it switched on and working before you start. Then it asks for the listing itself: a name up to 100 characters, a tagline up to 55, a description up to 2,000, one to five categories, your documentation URL, your privacy policy URL, a support contact, an icon, and the URL slug for your listing page. The slug is permanent once published.

Two things reject submissions more than anything else. A missing or incomplete privacy policy is an immediate no, and it has to cover what you collect, how it is used and stored, who else sees it, how long you keep it, and how to reach you. And a reviewer has to be able to use your connector end to end, which means a test account with realistic data and instructions detailed enough to follow without asking you anything.

You will also confirm who owns the API behind the connector. Wrapping someone else's API without their permission does not pass.

ChatGPT

Submit from the plugin portal, choosing the option for a plugin with an MCP server, and give it your production connector URL.

The publisher needs a verified individual or business identity on the OpenAI platform, and whoever submits needs Apps Management set to Write on their organisation role.

Domain verification is the step that involves us. OpenAI issues you a token and expects the domain serving your MCP server to return it, and only it, from /.well-known/openai-apps-challenge. Paste that token into Configuration → MCP and we serve it from your subdomain as plain text, nothing else in the body. Nobody else's firm can answer with it, and the shared address deliberately does not answer at all.

You also need demo credentials that work without two-factor or an email confirmation a reviewer cannot receive, and test cases: five showing your connector doing what it claims, and three showing it refusing or asking for clarification when it should.

Gemini

There is no directory to submit to. Google's consumer connectors are arranged by partnership, and the CLI gallery is neither vetted nor durable. What does work today is Gemini Enterprise, where your customer connects your server themselves from their own team settings. That path asks for Streamable HTTP and a certificate from a publicly trusted authority, both of which your connector already has.


Before you go live

Turning the connector off is not a pause button

Switching your MCP connector off revokes every live connection along with its tokens and keys, and switching it back on restores none of them. Every connected client has to reconnect from scratch.

That is deliberate — "disable" has to mean disable — but it means the switch is not something to toggle while investigating.

Past about ten tools, the client loads them on demand

Claude and ChatGPT both stop putting every tool definition in the model's context once a connector publishes more than roughly ten, and load them on demand instead. A tool that has not been loaded is not in the model's context at all — its description included. We publish around thirty, so assume your connector is always in this mode.

Two things follow from that. A catalogue written into a tool's description never reaches the model, which is why your knowledge base is listed in the connector's own instructions instead — those are sent when the client connects and always arrive. And a tool the model has not loaded is one it has to decide to load from its name and a short description, so name the subject in the first few words rather than opening with what the tool does to it.

Name your connector without spaces

The AI client, not Ask Clio, decides how a tool is addressed, and it builds that name from what your connector is called. A connector named Ask Clio produced ask_clio: where the client expected something else, and a smaller model failed three times in a row over it while a larger one worked it out. It costs nothing to avoid.

One conversation is one chat

Your clients' AI conversations arrive in Chat History split the way they happened, with a new chat starting after about half an hour of silence rather than everything landing in one endless thread.

Your nightly archiving email follows the same boundary, so a client who has three separate conversations in a day produces three emails rather than one covering all of them.

Every tool call a client makes lands there, and that includes searches of your knowledge base: what was asked, and what came back. So a review of what your clients have been doing shows the questions answered out of your own documents alongside the account lookups, rather than only the latter.

Tool changes and connected clients

Enable or disable a tool, or change its access level, and your connector serves the new list immediately. AI clients cache what they were given, though, so a client already connected may keep showing the old set until it reconnects or the person starts a new conversation.

One thing never changes on an existing connection: its read-only versus read-write level, which is fixed when the connection was granted. Moving a client from read-only to read-write requires them to reconnect.

Restricting which AI clients can connect

Under Configuration → MCP → Client Access Controls, "Allow unrecognized AI clients" is on by default: any client that completes the flow can connect. Turn it off and only the ones you list may start a connection.

The list you pick from is the set we recognise — Claude, ChatGPT, Perplexity, Cursor, Windsurf, Cline, VS Code, and scripts and SDKs. You can also type anything else, matched against whatever the client calls itself, so an internal agent of your own can be approved by name. If the client you want is not on the list, reach out to support and we will add it.

Be clear-eyed about what this buys you. A client's name is self-reported, so the setting keeps unexpected integrations out rather than determined ones. The IP allowlist beside it is the control that actually enforces. Use the name list for tidiness and the IP list for security.


Treat the request id as single-use

The authorization_request_id travels in the URL. If your client forwards that link, whoever opens it approves using their own session on your site, granting their own account. Not a data leak, but a confusing outcome — do not put the id anywhere it will be logged or shared.

How to host the AI authorization screen on your own site, with the Ask Clio CoPilot running as an iframe. Your customer approves the connection without leaving your page and without being sent to a Clio-hosted screen.

What you are building

When one of your customers connects an AI tool (Claude, ChatGPT) to their account, that tool starts an OAuth authorization. Clio needs a page to show the customer what is being requested so they can approve or deny it.

That page is yours. Clio redirects the browser to a route on your site; you already know who is signed in, so nobody has to authenticate again. You render the CoPilot in an iframe, it shows the consent card, and it hands the result back to the AI tool.

Before you start

Everything here is configured in the Ask Clio dashboard, under MCP Settings — available to anyone with a Firm Admin or Firm Employee role. Three fields matter:

  • Consent page URL — set this to your consent route. While it is empty, Clio sends your customers to a hosted fallback page that only your staff can complete. Include the trailing slash before any query string.

  • Allow client self-service — must be on, or the CoPilot tells your customers that connecting isn't available.

  • MCP enabled — the firm-level switch. Turning it off later revokes every live connection, not just new ones.

The same page shows your firm's connector URL, which is what your customers paste into their AI tool.

No tokens in that field

Consent page URL holds a plain route and nothing else — https://yourapp.com/ai-consent. It is a single static value for your whole firm, so a session token cannot go in it: tokens are per-customer and expire. Nor does client_id belong there.

Both are resolved inside your route, per request, at step 3 and step 4 below. That is where the flow becomes customer-specific — not in this setting. You never generate or send a consent link yourself; Clio sends each customer to this one route and your route works out who they are.

The flow

  1. AI tool → Clio

    The customer starts a connection

    They add your MCP server URL in Claude or ChatGPT. That tool calls Clio's /o/authorize, which validates the request and creates a short-lived authorization record.

  2. Clio → your site

    Clio redirects the browser to your route

    A top-level navigation to your consent_page_url with one parameter appended:

    Nobody generates that id by hand — not you, and not the AI tool. Clio creates the authorization record and appends its id on the way out, so it arrives on your route automatically.

    What is not automatic is getting it into the iframe. It lands on your page's URL; the embedded CoPilot reads its own frame URL, which is a different thing. Forwarding it inward is step 4, and it is the step most integrations miss.

  3. Your backend

    Identify the customer and mint a session token

    Authenticate them however you normally do. Then create an Ask Clio SDK session server-side — the same call you already make to embed the chat widget — and keep the returned token for the next step.

    Mint it per request

    Session tokens are per-customer and expire. Never hard-code one into consent_page_url or a static template; generate a fresh token each time this route is served.

  4. Your page

    Embed the CoPilot, carrying the request id

    The iframe URL needs three parameters: your client_id, the st session token from step 3, and the authorization_request_id from step 2. Whenever that third parameter is present, the CoPilot opens on the consent card instead of the chat.

    If you use the Ask Clio embed script rather than a raw iframe, append the same parameter to the URL you pass it and make sure the panel is open — a consent card behind a collapsed launcher looks like a dead end:

    Do not sandbox the frame

    Step 6 requires the frame to navigate the top-level page. If you must set sandbox, it has to include allow-top-navigation-by-user-activation alongside allow-scripts, allow-same-origin and allow-forms — or you must implement the message listener in step 6 instead.

  5. Your customer

    They approve or deny

    The CoPilot shows which AI tool is asking, whether the access is read-only or read & write, and every tool the connection grants. Their decision goes straight to Clio, authenticated with the session token — your page never handles any credential.

  6. Back to the AI tool

    The browser returns to the AI tool

    Clio replies with a redirect URL carrying the authorization code. This has to be a top-level navigation: pointing the iframe at claude.ai would try to load Claude inside your widget, and it refuses to be framed.

    The CoPilot navigates the top window for you, so an ordinary unsandboxed iframe needs no code here. If your page blocks top-level navigation, listen for the message instead and perform the redirect yourself:

    Always follow the redirect

    Send the customer to redirectTo even when it carries an error= parameter. A denial is a valid OAuth outcome and the AI tool knows how to present it. Check event.origin before acting on any message.

Constraints worth designing around

  • The request expires. An authorization request is valid for about ten minutes and can be used once. If your route bounces the customer through a login, they may return to an expired request — the CoPilot says so and asks them to start again from their AI tool.

  • One consent URL per firm. consent_page_url is a single value, so it must point at a route that works for every one of your customers rather than at anything user-specific.

  • Account details must be linked first. If your tools need values like a clearing account id and the customer's session does not carry them, the CoPilot refuses to connect rather than creating a connection that authenticates and then fails on every request.

  • Allow clipboard access. Without allow="clipboard-write" on the frame, copy buttons fall back to a legacy method that works but is less reliable.

If something goes wrong

What you see
Likely cause

The chat loads instead of the consent card

authorization_request_id never reached the iframe. Check the frame's src, not your page's URL.

Nothing visible; launcher stays collapsed

The panel was not opened. Call the SDK's open method when the parameter is present.

“This authorization request isn't valid”

The id is unknown or belongs to another firm — usually a truncated or re-used parameter.

“This request has expired or was already used”

Past the ten-minute window, or the customer double-submitted. They start again from the AI tool.

Approve succeeds, then a blank or refused panel

Top-level navigation was blocked. Implement the CLIO_CONSENT_COMPLETE listener.

“Connecting isn't available here yet”

Client self-service is off for your firm. Ask your Clio contact to enable it.

“Sign in through your firm to connect”

No st parameter, or the session expired. Mint a fresh token when serving the route.

The simpler alternative

If rendering consent inside your page is not a requirement, you can skip the embed entirely. Have your route mint the session token and then redirect top-level to the CoPilot:

The consent card fills the page, and the return trip needs no cooperation from you at all. Worth noting that either way the customer ends up at the AI tool when they approve — the only difference is whether the card renders inside your site for those few seconds.

Last updated