# How to verify a connected account in Stripe

- Tool: Stripe
- Difficulty: Advanced
- Time required: 20 minutes
- Compatibility: Stripe API v2024-12+, Node.js 18+
- Last updated: March 2026

## TL;DR

Connected accounts in Stripe require ongoing verification to remain active. Stripe sets requirements with deadlines — if not met, charges or payouts may be disabled. This guide covers how to check verification status, handle requirement updates, upload documents via the API, and monitor account.updated webhooks to keep your connected accounts compliant.

## Keeping Connected Accounts Verified and Compliant

Stripe requires connected accounts to verify their identity, business information, and banking details. Verification is not a one-time event — Stripe may request additional information based on regulatory changes, transaction volume, or periodic reviews. Failing to meet requirements by their deadlines can result in disabled charges or payouts. This guide covers the full verification lifecycle for connected accounts.

## Before you start

- Stripe account with Connect enabled
- At least one connected account (Express or Custom)
- Node.js 18 or later installed
- Stripe Node.js SDK: npm install stripe

## Step-by-step guide

### 1. Retrieve and inspect verification requirements

Check a connected account's requirements to see what information Stripe needs. Requirements fall into three categories: currently_due, eventually_due, and past_due.

```
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

async function getRequirements(accountId) {
  const account = await stripe.accounts.retrieve(accountId);

  console.log('Charges enabled:', account.charges_enabled);
  console.log('Payouts enabled:', account.payouts_enabled);
  console.log('\nCurrently due:', account.requirements.currently_due);
  console.log('Eventually due:', account.requirements.eventually_due);
  console.log('Past due:', account.requirements.past_due);
  console.log('Pending verification:', account.requirements.pending_verification);

  if (account.requirements.current_deadline) {
    const deadline = new Date(account.requirements.current_deadline * 1000);
    console.log('\nDeadline:', deadline.toISOString());
  }

  if (account.requirements.errors.length > 0) {
    console.log('\nErrors:');
    account.requirements.errors.forEach(e => {
      console.log(`  ${e.requirement}: ${e.reason} (${e.code})`);
    });
  }

  return account.requirements;
}

getRequirements('acct_connectedId');
```

**Expected result:** Console displays the account's charge/payout status, all requirement categories, deadline if any, and errors.

### 2. Upload an identity document

If a requirement like individual.verification.document is listed, upload an identity document (passport, driver's license) via the Files API and attach it to the account.

```
const fs = require('fs');

async function uploadVerificationDocument(accountId, filePath) {
  // Step 1: Upload the file to Stripe
  const file = await stripe.files.create({
    purpose: 'identity_document',
    file: {
      data: fs.readFileSync(filePath),
      name: 'id_document.jpg',
      type: 'image/jpeg',
    },
  });
  console.log('File uploaded:', file.id);

  // Step 2: Attach to the connected account
  const account = await stripe.accounts.update(accountId, {
    individual: {
      verification: {
        document: {
          front: file.id,
        },
      },
    },
  });

  console.log('Document attached. Pending verification:', 
    account.requirements.pending_verification);
  return account;
}

uploadVerificationDocument('acct_connectedId', './id_front.jpg');
```

**Expected result:** The document is uploaded and attached. The requirement moves from currently_due to pending_verification.

### 3. Update business and personal information

For requirements related to business details or personal information, update the account directly via the API.

```
async function updateAccountInfo(accountId) {
  const account = await stripe.accounts.update(accountId, {
    business_profile: {
      mcc: '5734',
      url: 'https://sellershop.com',
      product_description: 'Handmade crafts and artwork',
    },
    individual: {
      address: {
        line1: '456 Market St',
        city: 'San Francisco',
        state: 'CA',
        postal_code: '94105',
        country: 'US',
      },
      dob: { day: 10, month: 3, year: 1985 },
      ssn_last_4: '0000', // Test value
    },
  });

  console.log('Updated. Remaining requirements:', account.requirements.currently_due);
  return account;
}
```

**Expected result:** Account information is updated and the corresponding requirements are removed from currently_due.

### 4. Set up account.updated webhook monitoring

Verification happens asynchronously. Listen for account.updated events to track when requirements change, get fulfilled, or fail.

```
const express = require('express');
const app = express();

app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = req.headers['stripe-signature'];
  let event;
  try {
    event = stripe.webhooks.constructEvent(
      req.body,
      sig,
      process.env.STRIPE_WEBHOOK_SECRET
    );
  } catch (err) {
    return res.status(400).send(`Webhook Error: ${err.message}`);
  }

  if (event.type === 'account.updated') {
    const account = event.data.object;
    const id = account.id;

    // Check for newly failed verifications
    if (account.requirements.errors.length > 0) {
      console.log(`[${id}] Verification errors:`);
      account.requirements.errors.forEach(e => {
        console.log(`  ${e.requirement}: ${e.reason}`);
      });
      // Notify seller to resubmit
    }

    // Check if fully verified
    if (account.charges_enabled && account.payouts_enabled &&
        account.requirements.currently_due.length === 0) {
      console.log(`[${id}] Fully verified!`);
    }

    // Check for new deadline
    if (account.requirements.current_deadline) {
      const dl = new Date(account.requirements.current_deadline * 1000);
      console.log(`[${id}] Deadline: ${dl.toISOString()}`);
    }
  }

  res.json({ received: true });
});

app.listen(3000);
```

**Expected result:** Webhook handler logs verification errors, full verification status, and deadline changes for connected accounts.

## Complete code example

File: `verify-connected-account.js`

```javascript
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const express = require('express');
const app = express();

app.use(express.json());

// Get verification status for a connected account
app.get('/api/accounts/:id/verification', async (req, res) => {
  try {
    const account = await stripe.accounts.retrieve(req.params.id);
    const reqs = account.requirements;
    res.json({
      chargesEnabled: account.charges_enabled,
      payoutsEnabled: account.payouts_enabled,
      currentlyDue: reqs.currently_due,
      eventuallyDue: reqs.eventually_due,
      pastDue: reqs.past_due,
      pendingVerification: reqs.pending_verification,
      deadline: reqs.current_deadline
        ? new Date(reqs.current_deadline * 1000).toISOString()
        : null,
      errors: reqs.errors,
    });
  } catch (err) {
    res.status(400).json({ error: err.message });
  }
});

// Generate onboarding link to fix requirements
app.post('/api/accounts/:id/fix', async (req, res) => {
  try {
    const link = await stripe.accountLinks.create({
      account: req.params.id,
      refresh_url: `${req.headers.origin}/verify/refresh?acct=${req.params.id}`,
      return_url: `${req.headers.origin}/verify/done?acct=${req.params.id}`,
      type: 'account_onboarding',
    });
    res.json({ url: link.url });
  } catch (err) {
    res.status(400).json({ error: err.message });
  }
});

// Webhook for verification updates
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = req.headers['stripe-signature'];
  let event;
  try {
    event = stripe.webhooks.constructEvent(
      req.body, sig, process.env.STRIPE_WEBHOOK_SECRET
    );
  } catch (err) {
    return res.status(400).send(`Webhook Error: ${err.message}`);
  }
  if (event.type === 'account.updated') {
    const acct = event.data.object;
    console.log(`Account ${acct.id}:`);
    console.log(`  charges=${acct.charges_enabled} payouts=${acct.payouts_enabled}`);
    console.log(`  due=${acct.requirements.currently_due.length}`);
    console.log(`  errors=${acct.requirements.errors.length}`);
  }
  res.json({ received: true });
});

app.listen(3000, () => console.log('Verification server on port 3000'));
```

## Common mistakes

- **Only checking requirements at onboarding time and not monitoring ongoing changes** — undefined Fix: Requirements can change after initial onboarding. Set up account.updated webhooks to catch new requirements.
- **Uploading wrong file types for identity documents** — undefined Fix: Stripe accepts JPEG, PNG, and PDF for identity documents. File must be under 8MB. Ensure the image is clear and not blurry.
- **Ignoring pending_verification array** — undefined Fix: Items in pending_verification are being reviewed by Stripe. Do not ask the seller to resubmit until the review completes.
- **Not distinguishing between currently_due and eventually_due** — undefined Fix: Currently_due must be completed now. Eventually_due has a future deadline. Prioritize currently_due items.

## Best practices

- Build a verification status dashboard for your platform admins showing all connected accounts and their requirements
- Send automated email reminders to sellers when requirements approach their deadline
- For Express accounts, generate Account Links so Stripe handles the verification UI for you
- Store verification errors in your database for support troubleshooting
- Use test mode file tokens (file_identity_document_success, file_identity_document_failure) to test all verification scenarios
- If you manage many connected accounts, consider using RapidDev to build automated verification monitoring pipelines

## Frequently asked questions

### How often does Stripe request additional verification?

It varies. New requirements can appear due to regulatory changes, increased transaction volume, or periodic reviews. Some accounts may never get additional requests after initial onboarding.

### Can I verify a connected account on behalf of the seller?

For Custom accounts, yes — you can collect and submit all information via the API. For Express accounts, the seller must go through Stripe's hosted onboarding flow.

### What happens when a verification document is rejected?

The requirement appears in requirements.errors with a reason code (e.g., document_not_readable, document_expired). Generate a new Account Link for the seller to resubmit.

### How long does document verification take?

Automated checks complete in seconds. Manual document reviews take 1-3 business days. The account.updated webhook fires when review is complete.

### Can a connected account accept payments while verification is pending?

It depends. If charges_enabled is true, the account can still accept payments even if some requirements are pending. Check charges_enabled rather than the requirements list.

---

Source: https://www.rapidevelopers.com/stripe-guide/how-to-verify-a-connected-account-in-stripe
© RapidDev — https://www.rapidevelopers.com/stripe-guide/how-to-verify-a-connected-account-in-stripe
