The Stripe Connect error indicating that a platform lacks permissions on a connected account occurs when an API call uses the Stripe-Account header targeting an account (acct_...) that has not granted the necessary administrative capabilities, has had its authorization revoked, or is restricted by an API key scope. This prevents platforms from creating charges, initiating payouts, or modifying account metadata. Resolving this error requires verifying that the connected account’s onboarding capabilities are active, using an API key with Connect permissions, and correctly distinguishing between Custom, Express, and Standard Connect account access boundaries.
How do you fix the Stripe Connect error for missing platform permissions?
To resolve missing platform permissions on a connected account, verify that the account has fulfilled onboarding requirements for the requested capability (such as
card_paymentsortransfers), ensure your platform’s API key has write permissions for Connect, and confirm the account has not revoked platform access under its authorized applications.
Diagnostic Snapshot: Connected Account Platform Permissions
| Parameter | Diagnostic Value |
|---|---|
| Error Code | permission_denied, account_invalid, or HTTP 403 Forbidden |
| API Header | Stripe-Account: acct_... |
| Scope | Stripe Connect platforms (Marketplaces, SaaS, and Payment Facilitators) |
| Common Causes | Unfulfilled capability requirements, Standard account access limits, or revoked OAuth |
| Dashboard Location | Connect > Accounts > [Account ID] > Capabilities |
Diagnostic Path: Isolate the Missing Permission
API Error: Missing platform permissions on acct_...
│
├──► Check Connected Account Type (Dashboard > Connect > Accounts)
│ │
│ ├── Standard Account
│ │ ├── Attempting to update payout/bank details? ──► Platforms CANNOT modify Standard banking info
│ │ └── Did user revoke access? ───────────────────► Check for "account.application.deauthorized"
│ │
│ └── Custom or Express Account
│ ├── Account status incomplete? ──────────────► Missing required KYC / identity verification
│ └── Capabilities set to "inactive"? ─────────► "transfers" or "card_payments" not approved
│
└──► Check API Credentials
└── Using a Restricted API Key? ──────────────────► Ensure Key has "Write" access on Connect resources
How Connect Account Access Works
When a platform interacts with a connected account, it makes an authenticated API call using the platform’s Secret API key while passing the target account’s identifier in the request header:
curl <https://api.stripe.com/v1/charges> \
-u sk_live_...: \
-H "Stripe-Account: acct_1N098abcXYZ"
The permissions granted to the platform depend entirely on the account type and the account capabilities:
- Standard Accounts: Owned and operated by the connected user. The platform connects via OAuth. The user retains complete ownership of their Stripe Dashboard, banking information, and legal identity. Platforms cannot modify banking details, initiate payouts directly, or access resources the user has restricted.
- Express Accounts: Onboarding and identity verification are hosted by Stripe, but the platform controls payout timing and capability requests. Platforms manage the account via the API but cannot edit internal compliance verification directly.
- Custom Accounts: The platform is responsible for the entire user experience, including onboarding, identity collection, and compliance. The platform has broad API permissions, provided the account’s required capabilities are active.
If you attempt an action that exceeds the boundaries of your account architecture, Stripe returns:The provided key does not have permission to perform this action on the connected account.
Common Causes of Permission Failures
1. Inactive or Pending Capabilities (card_payments or transfers)
An account can be connected to your platform while still lacking the ability to process payments or receive funds. For example, if an account has not submitted its tax ID, beneficial ownership information, or business registration, the transfers capability remains inactive. If your platform attempts to transfer funds or create a destination charge on that account, Stripe denies the operation. If account verification is halted by identity compliance, troubleshoot using How to Resolve: Stripe “Identity Verification” Stuck on “Under Review”.
2. Standard Account Privilege Escalation
Developers often build features on Custom or Express test accounts and deploy them to Standard Connect accounts. For instance, attempting to call:
POST /v1/accounts/acct_.../external_accounts
This call works on Custom accounts because the platform manages the bank accounts. On a Standard account, this request fails immediately with a permissions error. Standard account holders must manage their own bank accounts through their native Stripe Dashboard.
3. Deauthorization by the Account Holder
Standard Connect accounts have the authority to disconnect from your platform at any time. A user can navigate to Settings > Authorized Applications within their personal Stripe Dashboard and revoke your platform’s access. Once revoked, any subsequent API call bearing that acct_... ID returns a permission error.
4. Restricted API Key (RAK) Scope Limitations
If your platform uses Restricted API Keys rather than the primary Secret Key, the key itself may lack permissions for Connect operations. If your key lacks access to the /v1/accounts or /v1/transfers endpoints, Stripe blocks the request at the platform level. For details on scoping keys correctly, see Fix: Stripe “Restricted Key” permissions blocking valid API calls.
Step-by-Step Resolution
Step 1: Retrieve and Inspect the Account Object
Run a direct GET request using your platform secret key to verify the account’s current capability state:
curl <https://api.stripe.com/v1/accounts/acct_1N098abcXYZ> \
-u sk_live_...:
Inspect the capabilities and requirements blocks in the JSON response:
{
"id": "acct_1N098abcXYZ",
"charges_enabled": false,
"payouts_enabled": false,
"capabilities": {
"card_payments": "inactive",
"transfers": "inactive"
},
"requirements": {
"currently_due": [
"individual.verification.document",
"tos_acceptance.date"
],
"disabled_reason": "requirements.past_due"
}
}
If capabilities.transfers or card_payments is inactive, look at the currently_due array. The connected user must provide this information before your platform can perform financial operations on their behalf. If automated balance routing subsequently fails, verify your integration settings with How to Resolve: Stripe “Connect” platform fee not being deducted.
Step 2: Route the User to Connect Onboarding
If an account is missing requirements, generate an Account Link to send the user through Stripe’s hosted verification flow:
const accountLink = await stripe.accountLinks.create({
account: 'acct_1N098abcXYZ',
refresh_url: '<https://example.com/reauth>',
return_url: '<https://example.com/return>',
type: 'account_onboarding',
});
// Redirect the merchant to accountLink.url
res.redirect(accountLink.url);
Once the user completes onboarding, Stripe updates their capabilities to active, and permissions are restored.
Step 3: Implement Webhook Handling for Deauthorization
Listen for authorization changes to ensure your database reflects when a connected account disconnects:
- Register an endpoint to receive Connect webhooks in Developers > Webhooks (Select Listen to events on Connected accounts).
- Listen for the event:
account.application.deauthorized. - When received, mark the merchant record in your database as disconnected and stop routing charges to their
acct_...ID.
if (event.type === 'account.application.deauthorized') {
const accountId = event.account; // The acct_... that unlinked
await db.merchants.update(
{ stripeAccountId: accountId },
{ isConnected: false, disconnectedAt: new Date() }
);
}
Step 4: Verify Restricted API Key Permissions
If the account is fully onboarded and active, check your platform’s API key:
- Go to Developers > API keys.
- If using a Restricted key, click the key name to inspect its permissions.
- Scroll to Connect: Ensure it is set to Write.
- Scroll to Accounts, Transfers, and Charges: Ensure each is set to Write.
- Save any changes, or switch to your primary Secret Key in your staging environment to confirm whether the key scope was causing the block.
If transfers continue to fail after permissions and keys are aligned, check for banking metadata discrepancies using Fix: Stripe “Payout Failed” (Incorrect Banking Metadata Fix).