> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kapso.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Business verification API

> Send a customer's business documents to Meta from the Platform API or MCP

<Note>
  Business verification is rolling out gradually. If these endpoints return `404` for a portfolio in your project, [contact support](mailto:support@kapso.ai).
</Note>

Endpoints are under `/platform/v1/whatsapp/portfolios/{portfolio_id}`, authenticated with your `X-API-Key`. `portfolio_id` is the Meta business portfolio ID of a production number in your project. [Get phone number](/api/platform/v1/phone-numbers/get-phone-number) returns it as `business_portfolio_id`, with a `business_verification` summary.

Each submission takes 1 to 3 documents, and each business portfolio gets 3 attempts, the same as [business verification in Kapso](/docs/whatsapp/business-verification). Kapso can only submit for businesses with a number connected through Kapso's Meta app. For numbers on [your own Meta app](/docs/platform/onboard-customers-own-meta-app), verify in Meta's [Security Center](https://business.facebook.com/latest/settings/security_center).

| Method | Path | Result |
| - | - | - |
| GET | `/business_verification` | Status, eligibility, attempts left, latest submission |
| POST | `/business_verification/submissions` | Send documents to Meta |
| GET | `/business_verification/submissions` | Your project's submissions, newest first |
| GET | `/business_verification/submissions/{submission_id}` | One submission, with its documents and Meta's reasons |

## Check the status

```bash theme={null}
curl https://api.kapso.ai/platform/v1/whatsapp/portfolios/1991231921410797/business_verification \
  -H "X-API-Key: $KAPSO_API_KEY"
```

Submit only when `allowed_actions.create_submission` is `true`. `status` is one of:

| Status | Meaning |
| - | - |
| `not_checked` | Kapso hasn't read the status from Meta yet |
| `not_verified` | No submission yet |
| `draft` | A teammate started a submission in the Kapso app |
| `in_review` | Meta is reviewing a submission |
| `in_review_external` | Someone submitted directly in Meta |
| `outcome_unknown` | Kapso can't confirm that Meta received the submission. Don't submit again |
| `changes_requested` | Meta rejected the last submission. If it was your project's, see `latest_submission.rejection_reasons` |
| `discarded` | Meta stopped the review without a decision |
| `verified` | Done |
| `revoked` | Meta removed the verification |
| `ineligible` | Kapso can't submit for this business. Verify in Security Center |
| `attempts_exhausted` | All 3 attempts are used. Verify in Security Center |

New values may be added, so handle unknown ones.

If the status is older than 30 seconds, Kapso reads it from Meta before it responds. `checked_at` is the last successful read. If Kapso couldn't read it for 6 hours, `unavailable` is `true` and `status` is the last known value.

## Submit documents

Send 1 to 3 PDF, JPEG, or PNG files of 5 MB or less. Together they must show the legal name and the address in the customer's Meta business portfolio. `roles` is optional and says what each file shows.

```bash theme={null}
curl -X POST https://api.kapso.ai/platform/v1/whatsapp/portfolios/1991231921410797/business_verification/submissions \
  -H "X-API-Key: $KAPSO_API_KEY" \
  -H "Idempotency-Key: acme-verification-1" \
  -H "Content-Type: application/json" \
  -d '{
    "documents": [
      { "source_url": "https://files.example.com/certificate.pdf", "roles": ["legal_name"] },
      { "source_url": "https://files.example.com/bank-statement.pdf", "roles": ["address"] }
    ]
  }'
```

`source_url` must be HTTPS. To upload the files instead, send `multipart/form-data`:

```bash theme={null}
curl -X POST https://api.kapso.ai/platform/v1/whatsapp/portfolios/1991231921410797/business_verification/submissions \
  -H "X-API-Key: $KAPSO_API_KEY" \
  -H "Idempotency-Key: acme-verification-1" \
  -F "documents[][file]=@certificate.pdf" \
  -F "documents[][roles][]=legal_name" \
  -F "documents[][file]=@bank-statement.pdf" \
  -F "documents[][roles][]=address"
```

The response is `202` with the submission and a `Location` header. `202` means Kapso accepted the request, not that Meta verified the business. Kapso sends the documents before it responds, so `state` is usually `pending`, which means Meta is reviewing them.

If `state` is `failed` with a `last_error`, nothing reached Meta and no attempt was used:

| `last_error.code` | Fix |
| - | - |
| `document_download_failed` | Kapso couldn't download a `source_url`. Check that it's public or signed, and not expired |
| `document_invalid` | A file isn't a PDF, JPEG, or PNG, is empty, or is over 5 MB |
| `meta_unavailable` | Kapso couldn't reach Meta. Try again with a new key |

For other codes, read `last_error.message`.

The API has no confirmation step. Get the customer's consent before you send their documents to Meta.

### Retries

`Idempotency-Key` is required, 1 to 255 bytes. If the request times out, retry with the same key and the same documents. You get the same submission back, and Kapso doesn't download or send anything again.

The same key with different documents returns `409` with `code: idempotency_conflict`. A renewed signed URL counts as a different document, so keep the original URL for retries. Use a new key only for a new attempt.

If `state` is `outcome_unknown`, Kapso is checking with Meta whether it received the documents. Keep polling, and don't create a new submission: it could use another attempt.

### Errors

| Status | `code` | Meaning |
| - | - | - |
| `400` | `invalid_idempotency_key` | `Idempotency-Key` is missing or longer than 255 bytes |
| `400` | `documents_invalid` | The request doesn't have 1 to 3 documents |
| `404` | `not_found` | No production number in your project has this portfolio, or the feature isn't enabled |
| `409` | `review_in_progress` | A submission for this portfolio is in review, from this or another project |
| `409` | `already_verified` | The business is verified |
| `409` | `attempts_exhausted` | All 3 attempts are used |
| `409` | `idempotency_conflict` | The key was used with different documents |
| `409`, `422` | `ineligible` | Kapso can't submit for this business |
| `422` | `document_invalid` | A document entry is invalid, for example an `http://` URL |

## Poll for the decision

```bash theme={null}
curl https://api.kapso.ai/platform/v1/whatsapp/portfolios/1991231921410797/business_verification/submissions/5b0f3c9e-7f1a-4c55-9a51-1f9f7d2b8e40 \
  -H "X-API-Key: $KAPSO_API_KEY"
```

Most reviews take a few minutes. Some take several hours. There's no webhook, and Kapso doesn't send email for submissions made with an API key. Poll every few minutes until `state` is `approved`, `failed`, `discarded`, or `revoked`.

When Meta rejects the documents, `state` is `failed` and `rejection_reasons` says why:

```json theme={null}
"rejection_reasons": [
  {
    "code": "LEGAL_NAME_NOT_FOUND_IN_DOCUMENTS",
    "requirement": "legal_name",
    "title": "Meta couldn’t find your legal name",
    "summary": "Legal name not found in your documents."
  }
]
```

There's one entry per reason. Each entry's `requirement` tells you which document to replace. Submit again with a new key. Each resubmission Meta receives uses an attempt.

## Documents and privacy

Submissions and their files belong to your project. Other projects with numbers in the same portfolio see the shared status and attempts, but not your submissions or Meta's reasons. Responses include file metadata, never the files.

Kapso keeps the files only to send them to Meta. It deletes them 30 days after Meta decides or the submission fails. `documents_purge_after` is the deletion date, and `documents_purged` is `true` once they're gone.

The list includes submissions made in the Kapso app. Drafts, editing a submission, and the Kapso Agent document check are only in the app.

## MCP

[Project MCP](/docs/whatsapp/mcp) has the same operations:

| Tool | Same as |
| - | - |
| `get_whatsapp_business_verification` | GET `/business_verification` |
| `create_whatsapp_business_verification_submission` | POST `/business_verification/submissions` |
| `list_whatsapp_business_verification_submissions` | GET `/business_verification/submissions` |
| `get_whatsapp_business_verification_submission` | GET `/business_verification/submissions/{submission_id}` |

Every tool takes `business_portfolio_id`. `create_whatsapp_business_verification_submission` also takes `idempotency_key` and `documents` with HTTPS `source_url`s. MCP can't upload files. Agents should ask the user before they call it.

Browser sign-in connections need `mcp:business_verification:read` to read, and `mcp:business_verification:submit` to submit. With browser sign-in, only project owners and admins can submit.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.