Stripe billing self-service for signed-in customers
Let your agent show signed-in customers their Stripe invoices and subscription, and open Stripe's customer portal so they can change their plan or payment method, or cancel: the restricted key, identity verification, what the agent sees and the access log.
If you bill your own customers with Stripe, your agent can answer their billing questions: it shows a signed-in customer their recent invoices and their subscription, and gives them a link to Stripe's customer portal, where they change their plan or payment method, or cancel. The agent never changes anything in Stripe itself. Every change happens in Stripe's own portal.
This uses your own Stripe account, connected with a restricted key you create. It has nothing to do with your intoCHAT subscription.
Before you start
You need:
- Identity verification set up on your site, with the agent's identity secret on your server.
- The customer portal set up in Stripe: in your Stripe Dashboard, open Settings, Billing, Customer portal, choose what customers may do there (for example update payment methods, switch plans or cancel), and save. Do this in live mode and, if you test with a test key, in test mode too.
Create a restricted key
A restricted key can do only what you allow it. intoCHAT refuses a full secret key (sk_…).
- In your Stripe Dashboard, open Developers, API keys, and click Create restricted key.
- Give it a name, for example "intoCHAT agent".
- Set these permissions and leave everything else at None:
| Resource | Permission |
|---|---|
| Customers | Read |
| Invoices | Read |
| Subscriptions | Read |
| Customer portal | Write |
- Optional: set Products to Read as well. The agent then names the plan by its product name; without it, it uses the price's nickname, or no name.
- Click Create key and copy it. It starts with
rk_live_, orrk_test_in test mode.
Customer portal: Write lets intoCHAT open a portal session for a customer. It doesn't let intoCHAT change subscriptions or payment methods itself.
Connect Stripe
- Open your agent and go to the Actions tab. The Stripe billing card is below Orders.
- Paste the key into Restricted key and click Test and connect.
intoCHAT checks the key by reading the ID of one customer, one invoice and one subscription, and checks whether a customer portal is set up. No customer data is shown. If a permission is missing, the card names it. If the portal isn't set up yet, the card connects and warns you. You can check keys up to 10 times in 10 minutes.
The key is stored encrypted and never shown again. The card shows its last four characters, whether it is a live or a test key, and your Stripe account's name when the key can read it.
- Test connection runs the same check with the saved key.
- Replace key connects with a new key. If the card says the saved key can't be read any more, the button reads Reconnect.
- Disconnect deletes the saved key from intoCHAT. To revoke the key itself, delete it in your Stripe Dashboard too.
Connecting, testing and disconnecting need the Admin or Owner role. They appear in the audit log as Integration connected and Integration disconnected. Transferring the agent to another account disconnects Stripe.
Tell intoCHAT which customer a visitor is
Identity verification signs only the visitor's user ID. The email and metadata your page passes beside it could be changed by a signed-in visitor in their own browser. So before showing any billing data, intoCHAT needs the Stripe customer, or the email, signed by your server for that user ID, with the same identity secret.
Pass one of these in the metadata of IntoChat.identify:
| Metadata key | Value |
|---|---|
stripe_customer_id | The visitor's Stripe customer ID, for example cus_Q1a2B3c4D5. |
stripe_customer_hash | HMAC-SHA256 of USER_ID:CUSTOMER_ID, keyed with the identity secret, in lowercase hex. |
email_hash | HMAC-SHA256 of USER_ID:EMAIL, keyed with the identity secret, in lowercase hex, where EMAIL is exactly the email you pass. |
intoCHAT finds the customer like this:
- With a valid
stripe_customer_idandstripe_customer_hash, it uses that customer, if it exists and isn't deleted. Nothing else is tried. - Otherwise, with a valid
email_hash, it looks for Stripe customers with exactly that email (Stripe compares emails as written). It uses the customer only if exactly one matches. - Otherwise, it finds nothing. The agent tells the visitor it couldn't find a billing account for their sign-in and asks them to contact you.
Passing the customer ID is the reliable choice. The email only works while each customer's email is unique in your Stripe account.
Node.js:
import { createHmac } from "node:crypto";
const secret = process.env.INTOCHAT_IDENTITY_SECRET;
const sign = (text) => createHmac("sha256", secret).update(text).digest("hex");
const userId = String(user.id);
const identity = {
userId,
userHash: sign(userId),
email: user.email,
metadata: {
stripe_customer_id: user.stripeCustomerId,
stripe_customer_hash: sign(`${userId}:${user.stripeCustomerId}`),
},
};
PHP:
<?php
$secret = getenv('INTOCHAT_IDENTITY_SECRET');
$userId = (string) $user->id;
$identity = [
'userId' => $userId,
'userHash' => hash_hmac('sha256', $userId, $secret),
'metadata' => [
'stripe_customer_id' => $user->stripe_customer_id,
'stripe_customer_hash' => hash_hmac('sha256', $userId . ':' . $user->stripe_customer_id, $secret),
],
];
Pass the result to IntoChat.identify on the page, as described in Identity verification. The metadata counts toward identify's limits of 20 keys and 2 KB.
What visitors can do
A signed-in visitor can ask the agent:
- About their invoices. The agent sees up to 10 recent invoices, newest first, and can share each one's date, number, amount and currency, status, and links to the invoice page and its PDF. Draft invoices aren't shown.
- About their subscription. The agent sees each current subscription's plan name, status, the end of the current period (the renewal date, or the end date if it is set to cancel) and whether it cancels at the end of the period.
- To change or cancel something. The agent opens Stripe's customer portal for them: a Manage billing button appears under its reply. The link works for a short time; if it expires, the visitor can ask again. In the portal they can do what you allowed in your portal settings, such as change their plan or payment method, update billing details or cancel. When they're done, the portal's return link takes them back to the website the chat is on (its address without the path), if it uses
https://and is one of your allowed domains when you have set any. Otherwise Stripe uses the default return link from your portal settings, if you set one.
A visitor who isn't signed in gets a short message asking them to sign in on your website first, in the language of the chat. The agent doesn't ask them for an email, a customer number or card details.
The agent can't cancel a subscription, change a plan, refund a payment or change a payment method itself. For any of these, it opens the customer portal.
Billing lookups need a saved conversation, so they aren't offered in a temporary chat. In the Playground, a test identity works like a real one, so it also needs the signed metadata above; lookups there are real lookups in your Stripe account.
What the agent sees
From Stripe, the agent gets only the fields listed under What visitors can do. It never gets the customer ID, the email address, the customer's name, address or phone number, card or bank details, tax IDs or invoice line items. intoCHAT copies the fields it passes on one by one, so nothing else reaches the agent.
In the conversation's "Why this answer", a lookup appears as Billing: invoices, Billing: subscription or Billing: customer portal.
Access log
intoCHAT logs each billing lookup and keeps the log for 90 days. Open Recent billing lookups in the Stripe billing card to see the last 25 entries, or click Export CSV for all of them. Everyone on your team can see it.
Each entry shows the time, what was read (invoices, the subscription, a customer portal link, or a connection test), the Stripe customer ID and whether it was found by the signed customer ID or the signed email, the outcome, and who: Visitor, or the person on your account who tested or connected Stripe. The log never holds invoice contents, amounts, emails or card details.
The outcomes help you check your setup:
- No signed customer ID or email: the visitor was signed in, but your page didn't pass a valid
stripe_customer_hashoremail_hash. - No customer found: the signature was valid, but the customer doesn't exist, was deleted, or no customer has that email.
- Several customers with this email: more than one Stripe customer has the email, so nothing was shown. Pass the customer ID instead.
- Stripe unavailable: Stripe couldn't be reached, or the key stopped working. Run Test connection.
Limits
- One Stripe account per agent.
- The agent only reads billing data and opens the customer portal. What a customer can change there is decided by your portal settings in Stripe.
- Up to 10 invoices and 3 current subscriptions per lookup.
- After a downgrade below Pro, the key stays saved but the agent stops using it until you upgrade again.
Next steps
- Sign your visitors in: Identity verification.
- Answer order questions from your store too: Order status and returns.