Stripe connector: read payments freely, refund only with approval
This page is for finance staff and whoever administers the Stripe account. It covers which restricted key to create, what each of the five tools returns, how amounts and currencies are converted, and what the approver checks before a refund goes to Stripe.
The connector calls the Stripe API at https://api.stripe.com with a bearer key. It reads PaymentIntents, the balance, customers and disputes, and can create refunds. Every request carries Stripe-Version: 2025-09-30.clover, so responses do not change when someone upgrades the account's default API version in the Dashboard. Stripe's changelog describes 2025-09-30.clover as the first release of the Clover line. An advanced field lets you set a different version. The pinned version requires OrgRelay 1.4.0 or later. The connector spec describes how a connector like this plugs into OrgRelay.
What staff can ask
- "What came in yesterday?" This calls
finance.paymentswith yesterday asdate_fromanddate_to. The dates are read as UTC days. - "How much is available to pay out, and how much is still pending?" This calls
finance.balance. It returns both lists, one entry per currency. - "Find the customer [email protected]." This calls
customers.search. A keyword containing@becomes an exact email match. - "Which disputes still need a response, and when is evidence due?" This calls
finance.disputes. By default it returns only open disputes, each with its evidence due date. - "Refund 20 euros of pi_3Q… as requested by the customer." This calls
finance.refundwithamount: 20andreason: requested_by_customer. It waits for approval.
The names follow the finance.* and customers.* domains in standard tools. That keeps questions about money consistent across Stripe, QuickBooks Online and Xero. A refund question often starts from an order, which the Shopify connector can look up first.
Tools
| Tool | Access | What it does | Key parameters |
|---|---|---|---|
finance.payments |
read | Lists PaymentIntents, newest first, with amount, status, customer ID and description | date_from, date_to, limit, cursor |
finance.balance |
read | Available and pending balance per currency | none |
customers.search |
read | Customers by email or name through the Search API | keyword (required), limit |
finance.disputes |
read | Open disputes by default, or all disputes, with amount, reason, status, charge and evidence due date | status (open default, all), limit, cursor |
finance.refund |
write · approval | Full or partial refund of one PaymentIntent | payment_intent (pi_…), amount (omit for full), reason (requested_by_customer, duplicate, fraudulent) |
Details that come from the code:
finance.paymentslists every PaymentIntent, including ones that never completed, such asrequires_payment_methodorcanceled. Check thestatuscolumn before adding amounts up.limitdefaults to 20 and caps at 100. The cursor is the last ID on the page, passed asstarting_after.customers.searchmatches names partially. A keyword without@becomesname~'…', a substring match. Single quotes in the keyword are removed. The tool returns one page with no cursor.finance.disputesfilters on its side. Stripe's dispute list cannot be filtered by status, so forstatus: openthe connector reads disputes 100 at a time and keeps those inneeds_response,warning_needs_response,under_revieworwarning_under_review. One call reads at most 10 pages. If it stops before findinglimitopen disputes, it returns a cursor so the next call continues where it left off.status: allreturns every dispute, newest first.- Amounts are shown in major units. The connector follows Stripe's published currency rules: zero-decimal currencies such as JPY, KRW and VND are shown as they are, and the rest are divided by 100. UGX and ISK have no fractional units but are still sent to Stripe as two-decimal values ending in 00, and the refund tool converts them that way.
Credentials and permissions
There is one field: the API key. Use a restricted key (rk_live_…, or rk_test_… in a sandbox). Stripe recommends restricted keys over secret keys, and in particular for AI agents. A secret key (sk_live_…) also works, but it can do anything in the account.
Set these permissions on the key, and leave everything else at None:
| Resource | Read-only setup | With refunds |
|---|---|---|
| PaymentIntents | Read | Read |
| Balance | Read | Read |
| Customers | Read | Read |
| Disputes | Read | Read |
| Refunds | None | Write |
Balance Read is needed in every case, because the connection test calls /v1/balance. The test also tells you whether the key is live or sandbox, and OrgRelay shows that next to the connection name. The refund tool reads the PaymentIntent before refunding, which is why PaymentIntents Read stays on.
Restricted keys have no built-in expiry. Stripe lets you rotate a key with a grace period of up to seven days, during which both keys work. That gives you time to paste the new key into OrgRelay. Stripe also lets you attach an access policy that only accepts requests from known IP addresses. If the OrgRelay machine has a fixed public address, use one. OrgRelay stores the key encrypted and shows only its last four characters; see auth and the security model.
What the approver sees before a refund
finance.refund is the only write tool, and it always creates an approval request. Nothing reaches Stripe until the owner or a designated approver accepts it. The approver sees:
- the PaymentIntent ID;
- the amount in major units, or no amount, which means a full refund of whatever is still refundable;
- the reason, if given.
Before approving, open the PaymentIntent in the Stripe Dashboard and check what has already been refunded. A full refund on a partly refunded payment refunds the rest. After approval, the connector fetches the PaymentIntent to learn its currency and converts the amount to minor units. It then posts to /v1/refunds with the header Idempotency-Key: orgrelay-approval-<approval id>. If the same approved request is retried, Stripe returns the original refund instead of creating a new one. The result shows the refunded amount, the currency and the refund status, for example pending for some payment methods.
The general approval flow is on approvals and writes. For how finance teams use OrgRelay day to day, see the finance agent.
Set it up
- In the Stripe Dashboard, open Developers → API keys and click Create restricted key. Start in a sandbox if you want to try the refund tool first.
- Name it "OrgRelay" and set the permissions from the table above.
- Click Create key, complete the two-factor check, and copy the key. You cannot reveal a live restricted key you created yourself a second time.
- Optionally attach an access policy limited to the OrgRelay machine's IP address.
- In OrgRelay, open Admin → Business systems → App directory, pick Stripe, paste the key and click Connect. The connection shows "live" or "test" mode.
- Grant the connector to the finance role. Switch
finance.refundoff for roles that should only look, such as customer support. Support can then see a payment's status but must ask finance for the refund.
When you build an internal tool next to Stripe, the quickstart and the connector check show how OrgRelay expects connectors to behave, including idempotent writes.
Limits and things it does not do
Stripe's rate limits are 100 requests per second in live mode and 25 in a sandbox, with most single endpoints at 25 per second. The Search API used by customers.search allows 20 reads per second. Stripe also expects read requests to average no more than 500 per transaction over 30 days, with at least 10,000 a month for any account. An assistant answering staff questions stays far below these figures. OrgRelay caps each connection at 120 calls per minute by default and pauses for 60 seconds after three failures in a row. If Stripe returns 429, OrgRelay waits for Retry-After, or 60 seconds.
The connector does not:
- create charges, PaymentIntents, invoices, subscriptions, payouts or transfers;
- submit dispute evidence or accept a dispute;
- read card details, payment method details or customer addresses;
- act on Connect connected accounts, because it sends no
Stripe-Accountheader.
Results are cut to about 12,000 characters before the AI reads them, so ask for a date range rather than "all payments". For event-driven work, such as reacting to a new dispute, see events. Internal tools that sit next to Stripe can be served to OrgRelay over the MCP transport.
Official MCP server and OrgRelay
Stripe runs an official MCP server at https://mcp.stripe.com. It authenticates with OAuth or with an agent API key. Stripe has announced that from December 2026 the MCP server will stop accepting full secret keys and restricted keys without the Agent tag. The server offers stripe_api_read and stripe_api_write, which cover a long list of API methods, plus account, analytics and documentation tools. Some actions, refunds among them, carry Stripe's "Human confirmation" badge: Stripe asks you to approve them in the Dashboard, and the agent retries after approval.
That is a capable setup for a single user at a desk. OrgRelay can attach the same server as a third-party MCP connection if you prefer Stripe's broader tool set, authenticating with an agent API key sent as a bearer token in the request headers. Stripe's interactive OAuth sign-in, which uses PKCE, cannot be completed from an OrgRelay connection. Either way, OrgRelay adds what a company with many staff needs: grants per role and department, an approval step for every write tool across every system, one audit log that also covers your store and accounting connectors, and all of it running on the company's own machine. See human in the loop and enterprise patterns for how the two approval models fit together, and Claude Desktop if staff also use Stripe's connector there.
Common questions
Which restricted key permissions does the connector actually use?
PaymentIntents Read, Balance Read, Customers Read and Disputes Read for the read tools, plus Refunds Write for finance.refund. Balance Read is required even for a read-only setup, because the connection test calls /v1/balance. Charges permission is not used.
Can a refund run twice if an approver clicks twice or the network drops?
The connector sends the OrgRelay approval key as Stripe's Idempotency-Key header, so a retried request with the same key returns the first result instead of creating a second refund. A second, separate approval for the same payment would be a new refund, so approvers should check the refunded amount before approving.
Should we tag the key as an agent key in Stripe?
You can. Agent-tagged keys authenticate like any restricted key, but Stripe applies its own approval rules to them, and the default rules cover refunds. A refund approved in OrgRelay may then also wait for a reviewer in Stripe. Decide which approval step you want, or keep both on purpose.