KYB

Know Your Business (KYB) verifies that a business account is a real legal entity and that the people who own and control it are who they say they are. Frame models it as a capability on a business account - you request kyb, the account holder supplies the entity details and the owner roster, and Frame runs the business check against the legal entity.

KYB is not one check, it's two layers. Frame verifies the entity; each listed owner and controller runs their own KYC as a separate individual account in parallel. The business check does not start until every one of them has passed. That ordering is the single most surprising property of KYB for anyone arriving from KYC, and it explains nearly every KYB that appears stuck.

When you need KYB

Request kyb when your flow pays money out to a business. card_receive and bank_account_receive on a business account both depend on it - the same gate KYC puts on the individual receive capabilities. Request either one on a business account and Frame pulls kyb in; you don't have to ask for it separately.

kyb is also requestable on its own, when you need the entity verified independently of any payout capability.

kyb is business-only. Requesting it on an individual account is rejected - individuals run KYC. A business account taking payments in (card_send, bank_account_send) needs no KYB; the gate is on money leaving Frame, not money arriving.

Required information

KYB collects in two parts, tracked as two separate requirements on the capability: business_info_collected for the entity and beneficial_owners_collected for the roster.

The entity:

FieldWhere it lives on the Account
Legal business namebusiness.legal_business_name
Business typebusiness.business_type
EINbusiness.ein - stored encrypted; only ein_last_four is returned via the API
Business emailbusiness.email
Legal addressbusiness.address - line 1, city, state, postal code, country
Physical addressbusiness.physical_address - only when the business declares it differs from the legal address

The physical address is conditional. A business that sets same_physical_and_legal_address to false owes the full physical address block; a business that leaves it true owes nothing further.

The owner roster: one entry per person, each carrying name, email, date of birth, address, one or more roles (owner, controller, or both), and a percent ownership.

The roster has to satisfy all of these before beneficial_owners_collected is satisfied:

  • At most four people.
  • At least one person listed as an owner.
  • At least one person listed as a controller. One person can be both.
  • Total percent ownership across the roster no greater than 100.
  • Every listed person identity-complete - no outstanding invites.
  • The roster confirmed by the account holder. Confirmation is re-stamped on every confirm, because the roster stays editable afterwards.

Prefill anything you already hold at account-creation time. What you don't have surfaces in the capability's currently_due array, and the onboarding session collects it.

The flow

KYB runs through a hosted onboarding session, same as KYC, with one extra fan-out: the owners.

  1. Create the business account with kyb in the capabilities array and any entity fields you already have. card_receive or bank_account_receive pull kyb in on their own.
  2. Create an onboarding session for the account. Frame returns a URL. Redirect the person driving the onboarding - typically an owner or the controller.
  3. The driver completes Business details (the entity block) and Owners and controllers (the roster). They enter each owner and either supply that owner's identity details inline or send them an emailed invite.
  4. Every owner and controller completes their own KYC. The driver does theirs in the same session, on the Personal info step. Everyone else gets a self-complete link by email against their own individual account.
  5. The business check runs. Once the entity block, the roster, and every owner's KYC have all landed, Frame submits the business to its verification provider.
  6. Confirm activation. Subscribe to capability.activated / capability.disabled on the kyb capability, or poll the account. As with KYC, the driver's redirect fires when they click through - not when the check has resolved.

Steps 3 through 5 are strictly ordered. An account that has collected everything and still reads pending is almost always waiting on step 4.

Walk-through with code: Run onboarding.

Outcomes

The kyb capability uses the standard capability lifecycle:

  • active - the entity verified. Any payout capability that depended on kyb activates behind it.
  • disabled - the business check returned a terminal rejection. The capability carries disabled_reason: "kyb_verification_failed". This is the only failure state that ends the flow.
  • pending - Frame is waiting on something. For KYB this covers four distinct situations, and telling them apart is the most useful thing you can do with the integration; see Reading a pending KYB.

A provider error or an incomplete result does not disable the capability. Both leave it pending so the check can be re-run - a transient provider fault should not decline a business.

Reading a pending KYB

What's happeningHow to tellWhat to do
The entity or the roster is incompletecurrently_due names business_info_collected or beneficial_owners_collectedPut the driver through an onboarding session to finish the outstanding step
Owners are still verifyingCollection requirements satisfied, but an owner's own kyc capability isn't active yetChase the outstanding owner. Resend their invite
The business check is in flightEverything satisfied, kyb_verification outstandingNothing. Wait for capability.activated or capability.disabled
The check is in reviewSame as in flight, but hours have passedContact Frame support with the account ID

The last two are indistinguishable from the API - review is not a capability status. The difference is time. A check in flight resolves in seconds to minutes; a review does not, and no amount of re-requesting the capability moves it.

How Frame triages a failed check

The verification provider returns a status for the business, not a list of reason codes. Frame classifies that status into one of five dispositions:

DispositionCapability lands onWhat it meansYour move
PassactiveThe entity verified against the provider's sources.Nothing.
RejecteddisabledA terminal decision on the entity. disabled_reason: "kyb_verification_failed".Decline per your policy. This does not reopen on its own.
ReviewpendingThe run is open with a human reviewer, who is what will conclude it.Wait, then contact Frame support. Nothing on your side unblocks it.
IncompletependingThe provider could not reach a decision on the data submitted.Correct or complete the entity details, then contact support to re-run.
Provider errorpendingThe provider was unreachable or returned no usable answer.Transient. Frame re-checks; nothing to do.

An open review outranks whatever status the provider mirrored back, because the reviewer is what concludes that run.

KYB has no business reason codes. Individual KYC exposes a rich reason-code vocabulary because the identity provider publishes one; the business side does not. A business check tells you what happened, not which of thirty signals tripped. Don't build branching that expects codes on a kyb failure.

Reading a business verification in the dashboard

A business account's identity detail page in frameOS is headed Business identity and carries four panels plus a sidebar:

  • Profile - the entity as submitted: legal business name, doing-business-as, business type, last 4 of EIN, email, phone, website, and the addresses. Read this first on a failed check; a transposed EIN explains more failures than anything else will.
  • Business representatives - the roster, one row per person, with their roles, percent ownership, and a KYC badge of Verified, Failed, or Pending drawn from that person's own latest identity verification. This is the panel that answers "which owner is holding this up."
  • Verifications - one row per check ever run against this account, newest first. KYB rows are typed KYB and carry a status badge.
  • Info panel - the account's overall status and when it was last touched. For a business, this reflects the latest run: Pending, Needs review, Verified, Failed, or Errored.
  • Timeline - the same runs as a chronological feed, including when a run was flagged for manual review.

Risk signals are not rendered for business accounts. The panel exists on the individual identity page, where the provider supplies per-signal findings; there is no business equivalent, and the KYB rows in the Verifications table carry no reasons column.

Re-verification

Editing the entity profile re-evaluates the kyb capability against the new data. It does not automatically re-submit the business to the verification provider - a capability that failed can activate later, but the new decision arrives from the provider, not from your edit.

Amending the owner roster is the larger change: it alters what the provider is being asked to judge, and it re-opens the collection requirement. Adding a person means that person now has to pass their own KYC before the business check will run again. Removing an invited owner tears down their invite session, so their link stops working.

Frame keeps every run. The capability surface reflects the current state; the dashboard's verification timeline holds the history.

Scope - what KYB checks

KYB verifies the entity claim:

  • The business exists as a registered legal entity under the name and type given.
  • The EIN reconciles against that entity.
  • The declared owners and controllers are linked to the entity with the ownership stakes given.

KYB does not check:

  • Each owner's personal identity. That is their own KYC, run separately against their individual account - KYB depends on the result but doesn't perform it.
  • Whether the business is licensed or permitted for the activity it does.
  • Creditworthiness, financial health, or anything about the business's ability to pay.
  • Whether the business address is currently valid (that's address_verification).

Gotchas

Symptom: the kyb capability sits pending, currently_due is empty, and the entity and roster both look complete. Why: one of the listed owners or controllers has not finished their own KYC, and the business check does not start until all of them have. Owner KYC is not surfaced in the business account's currently_due. Fix: open the account's Business representatives panel in frameOS and find the row whose KYC badge isn't Verified. Chase that person.

Symptom: an owner was invited by email weeks ago and never completed. Why: the invite link is a long-lived, owner-scoped onboarding session, and people lose emails. Fix: resend the invite. The resend slides the existing session's expiry forward and re-mails the same link rather than minting a new one, so an owner who got partway through resumes where they left off.

Symptom: the business is pending even though the person who did the onboarding shows as verified. Why: that person is one owner. The driver's KYC passing says nothing about the other three. Fix: check every row of the roster, not just the driver's.

Symptom: the roster was confirmed successfully, but the business check never runs and nothing in currently_due explains it. Why: an owner was saved without a percent ownership. The collection requirement accepts a blank percentage - it only enforces that the total doesn't exceed 100 - but the provider submission requires an ownership stake for every owner and refuses to run without one. Fix: edit the roster and set an explicit percentage on every listed owner, including 0 where an owner holds no equity.

Symptom: business details were submitted, but currently_due still names business_info_collected. Why: the business declared that its physical address differs from its legal address, which pulls the five physical-address fields into the requirement, and they haven't all been filled. Fix: complete the physical address, or set same_physical_and_legal_address back to true if the addresses actually match.

Symptom: you requested kyb and bank_account_receive together and only kyb shows up in the response. Why: Frame stages dependent capabilities - bank_account_receive isn't evaluated until kyb activates. Fix: retrieve the account again once kyb is active.

Symptom: you got capability.disabled for kyb and the payload doesn't say why. Why: the capability webhook payload carries identity and status, not disabled_reason. Fix: retrieve the capability after the webhook fires and read disabled_reason off the response.

Symptom: you're looking for reason codes on a failed KYB the way you would on a failed KYC. Why: there aren't any. The business provider returns a status; Frame's business failure vocabulary is deliberately coarse. Fix: read the disposition - rejected, review, incomplete, or provider error - and treat rejected as the only terminal one.

Reference

For the full API surface, see POST/v1/accounts and POST/v1/onboarding_sessions.

Frame Assistant

Ask anything about Frame's APIs and products