Universal KYB

This guide traces the Universal KYB flow from the creation of the business entity through pack capture, document upload, and review submission to the final compliance decision. It covers request formats, response formats, and the status transitions of the compliance case.

Purposes: This guide follows the onboarding journey of a business entity through Universal KYB and maps each stage to its API call, request, response, and resulting case state. It covers every endpoint in the Universal KYB onboarding flow in call order and separates the one time entity creation and pack capture from the amendments and document uploads that repeat until the case closes.


When to Use This

Use this guide when you need to:

  • Create the business entity that a compliance case belongs to
  • Store and amend the complete KYB pack, including beneficial owners, questionnaire, and enhanced diligence declarations
  • Upload the required company records and the identity document of every declared beneficial owner
  • Submit the assembled case for compliance review
  • Receive the compliance decision through an event subscription

Overview

Universal KYB builds a compliance case around a business entity and reports every status change of that case through an event subscription. The KYB pack holds the legal profile of the business, the declared beneficial owners, the due diligence questionnaire, and the enhanced diligence declarations. Each declared beneficial owner becomes an individual record that carries the identity documents for that person.

With the event subscription in place, a single onboarding starts with the creation of the business entity and the capture of the pack, continues with amendments while the case stays editable, and moves on to the upload of the supporting files. Company records attach to the business record, and identity records attach to the individual record of the owner they belong to. The case then goes to compliance review as one closed submission.

A business entity accepts one pack submission, so every later change goes through an amendment that stores a new version and preserves history. Replacing the declared owners rebuilds their individual records and discards the identity files held against the previous ones. The case stops accepting edits once it reaches compliance review, and the same event subscription delivers the decision for every case in the program.


Prerequisites

  1. Use a valid Reap compliance API key in every request
  2. Enable Universal KYB for the program before the first production case
  3. Configure the compliance base host that matches the target environment
  4. Collect the beneficial owner records and the supporting files before the first call
  5. Expose a destination that accepts event deliveries when the client needs the decision without contacting support

Key Concepts

Business Entity

  • Business entity represents the company being onboarded and owns the KYB case
  • Every KYB call addresses the entity through the path segment entityId
  • Company documents upload against this entity rather than against an individual

KYB Pack

  • KYB pack holds the legal profile of the business together with the optional ddq and edd sections
  • The pack accepts one creation call per business entity and every later change becomes an amendment
  • Each stored change creates a new submittedRequirementId so the case keeps its history

UBO Declaration

  • uboDeclaration lists the beneficial owners that the client declares for the business
  • Each declared owner is created as an individual entity that is returned in uboEntities
  • Supplying the array replaces the whole set and discards the identity files held against the previous ids

Document Requirement

  • Document requirement identifies the KYB slug that a set of uploaded files satisfies
  • A required slug gates the submission while an optional slug supports the review without gating it
  • A company requirement appends files across uploads while ubo-kyc replaces the files held for the same document kind
    Document TypeRequired For SubmissionUpload AgainstPurpose
    certificate-of-incorporationYesBusiness entityProvides the certificate of incorporation or the jurisdictional equivalent
    company-profileYesBusiness entityProvides the registrar profile with registered particulars, shareholders, and officers
    shareholding-chartYesBusiness entityProvides the shareholding structure chart
    ubo-kycYes, for each declared ownerIndividual entityProvides the identity document of one beneficial owner
    register-of-directorsNoBusiness entityProvides the register of directors
    business-registryNoBusiness entityProvides the business registry extract
    source-of-funds-supporting-docNoBusiness entityProvides an enhanced diligence attachment for source of funds
    source-of-wealth-supporting-docNoBusiness entityProvides an enhanced diligence attachment for source of wealth
    ownership-structure-chartNoBusiness entityProvides the ownership chart that shareholding-chart supersedes
    board-resolutionNoBusiness entityProvides the board resolution when compliance requests it

KYB Submission

  • Submission checks completeness, locks the stored payload, and queues the case for compliance review

  • Presence of a document is checked rather than approval of that document

Case Status

  • Case status shows where the case sits between assembly and the final compliance decision
  • PENDING_SUBMISSION accepts pack changes and document uploads, and UNDER_REVIEW locks both
  • PENDING_ADDITIONAL_INFO, APPROVED, REJECTED, and CANCELLED_BY_CLIENT each raise a status event

Flow Overview

The event subscription runs once for the program before the first case opens, the entity creation and the pack capture run once for each business, the amendments and the document uploads repeat while the case stays editable, and the review submission runs once to close the case.

  • Status notification uses POST /notification to register the destination that receives each decision event
  • Entity creation uses POST /entity to create the business entity that every later call addresses
  • Pack capture uses POST /entity/entityId/ukyb to store the complete pack and create the individual entities for the declared owners, and PATCH /entity/entityId/ukyb to deep merge a later change into the stored payload
  • Document collection uses POST /entity/entityId/ukyb/documents to file each required company record against the business entity and the identity record of every declared owner against the individual entity of that owner
  • Case closure uses POST /entity/entityId/ukyb/submit to check completeness, lock the payload, and queue the case for compliance review

API Summary

ActionEndpointMethodUse Case
Subscribe to KYB notifications/notificationPOSTCreates the subscription that delivers each KYB status event
Create business entity/entityPOSTCreates the business entity that owns the KYB case
Create KYB pack/entity/entityId/ukybPOSTStores the complete KYB pack and creates an individual entity for each declared owner
Amend KYB pack/entity/entityId/ukybPATCHUpdates part of the stored payload while the case remains editable
Upload KYB documents/entity/entityId/ukyb/documentsPOSTStores the files that satisfy one document requirement
Submit KYB for review/entity/entityId/ukyb/submitPOSTCreates the review submission that locks the case

Webhook Summary

EventFired WhenClient Action
KYB_STATUS_CHANGEDA KYB case moves to a new statusUpdate the stored KYB status and take the next onboarding step

Universal KYB Onboarding

Step 1: Subscribe To KYB Notifications

Register the destination that receives every KYB status event. Use this step once per destination.


Call the Subscribe To KYB Notifications Endpoint

Use POST /notification to register the destination that receives each KYB status event.


Sample Request (cURL)

curl --request POST \
  --url https://sandbox-compliance.api.reap.global/notification \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --header 'x-reap-api-key: ********' \
  --data '{
    "notificationChannel": "WEBHOOK",
    "notificationTypes": ["kyb_status_change"],
    "webhookUrl": "https://example.com/webhooks/reap"
  }'

Key Input

Parameter NameTypeDescription
notificationChannelstringSpecifies the delivery channel for the subscription
notificationTypesarrayLists the event types that the destination receives
webhookUrlstringProvides the destination that receives each event

Sample Response

{
  "notificationChannel": "WEBHOOK",
  "notificationTypes": ["kyb_status_change"],
  "webhookUrl": "https://example.com/webhooks/reap"
}

Key Output

Parameter NameTypeDescription
notificationTypesarrayLists the event types that the subscription now delivers
webhookUrlstringShows the destination stored for the subscription

Sample Webhook Payload

{
  "eventType": "kyb_status_change",
  "eventName": "kyb_status_changed",
  "data": {
    "eventId": "<string>",
    "message": "KYB approved",
    "entityId": "<string>",
    "status": "APPROVED",
    "cardIssuanceEnabled": true,
    "timestamp": "2026-01-01T00:00:00Z",
    "occurredAt": "2026-01-01T00:00:00Z",
    "sequence": 1,
    "schemaVersion": 1
  }
}

Step 2: Create Business Entity

Create the record that the compliance case belongs to. Use this step once for each business, because every later call in the flow addresses the identifier that it returns.


Call the Create Business Entity Endpoint

Use POST /entity to create the business entity that owns the KYB case.


Sample Request (cURL)

curl --request POST \
  --url https://sandbox-compliance.api.reap.global/entity \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --header 'x-reap-api-key: ********' \
  --data '{
    "externalId": "<string>",
    "type": "BUSINESS"
  }'

Key Input

Parameter NameTypeDescription
externalIdstringIdentifies the business inside the client system
typestringSpecifies the kind of entity that the call creates

Sample Response

{
  "id": "<string>",
  "externalId": "<string>",
  "businessId": "<string>",
  "type": "BUSINESS"
}

Key Output

Parameter NameTypeDescription
idstringIdentifies the business entity for the KYB pack call
businessIdstringIdentifies the managing business that holds the entity
typestringShows the kind of entity that the call created

Step 3: Create KYB Pack

Store the complete KYB pack for the business entity in a single call. Use this step once per business entity to open the case and to create an individual record for every declared beneficial owner.


Call the Create KYB Pack Endpoint

Use POST /entity/entityId/ukyb to store the complete KYB pack for a business entity.


Sample Request (cURL)

curl --request POST \
  --url https://sandbox-compliance.api.reap.global/entity/entityId/ukyb \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --header 'x-reap-api-key: ********' \
  --data '{
    "legalBusinessName": "<string>",
    "legalFormOfCompany": "PRIVATE_LIMITED",
    "businessRegistrationNumber": "<string>",
    "uboDeclaration": [
      {
        "externalUserId": "<string>",
        "ownershipPct": 100,
        "identity": {
          "firstName": "<string>",
          "middleName": "<string>",
          "lastName": "<string>",
          "fullName": "<string>",
          "dob": "1992-04-15",
          "nationality": "MEX"
        },
        "document": [
          {
            "documentCategory": "IDV",
            "type": "PASSPORT",
            "number": "A12345678",
            "country": "MEX",
            "issuingDate": "2020-01-10",
            "expiryDate": "2030-01-09"
          }
        ],
        "address": {
          "country": "MEX",
          "postCode": "01000",
          "town": "<string>",
          "street": "<string>",
          "state": "<string>",
          "buildingNumber": "<string>",
          "formattedAddress": "<string>"
        }
      }
    ],
    "registeredAddress": {
      "line1": "<string>",
      "line2": "<string>",
      "city": "<string>",
      "postalCode": "01000",
      "country": "MEX"
    },
    "principalPlaceOfBusinessAddress": {
      "line1": "<string>",
      "line2": "<string>",
      "city": "<string>",
      "postalCode": "01000",
      "country": "MEX"
    },
    "businessWebsiteUrl": "https://example.com",
    "validEmailDomains": ["example.com"],
    "lineOfBusiness": "PROFESSIONAL_SERVICES",
    "dateOfIncorporation": "2015-06-01",
    "ddq": {
      "cardAuthorities": [
        {
          "fullName": "<string>",
          "role": "<string>"
        }
      ],
      "expectedSpendProfile": {
        "spendBuckets": [
          {
            "name": "<string>",
            "expectedSpendUsd": 25000,
            "jurisdictionIso": "<string>",
            "txnPattern": {
              "frequency": "monthly",
              "avgTicketUsd": 2000,
              "peakDays": ["MON"]
            }
          }
        ]
      },
      "numberOfEmployees": 100
    },
    "edd": {
      "sourceOfFundsDeclaration": "<string>",
      "sourceOfWealthDeclaration": "<string>"
    }
  }'

Key Input

Parameter NameTypeDescription
entityIduuidIdentifies the business entity that receives the KYB pack
uboDeclarationarrayLists the beneficial owners declared for the business
uboDeclaration.document.typestringSpecifies the identity document kind that the upload call must match
lineOfBusinessstringSpecifies the business classification code

Sample Response

{
  "submittedRequirementId": "<string>",
  "payload": {
    "legalBusinessName": "<string>",
    "legalFormOfCompany": "PRIVATE_LIMITED",
    "businessRegistrationNumber": "<string>",
    "uboDeclaration": [
      {
        "externalUserId": "<string>",
        "ownershipPct": 100,
        "identity": {
          "firstName": "<string>",
          "middleName": "<string>",
          "lastName": "<string>",
          "fullName": "<string>",
          "dob": "1992-04-15",
          "nationality": "MEX"
        },
        "document": [
          {
            "documentCategory": "IDV",
            "type": "PASSPORT",
            "number": "A12345678",
            "country": "MEX",
            "issuingDate": "2020-01-10",
            "expiryDate": "2030-01-09"
          }
        ],
        "address": {
          "country": "MEX",
          "postCode": "01000",
          "town": "<string>",
          "street": "<string>",
          "state": "<string>",
          "buildingNumber": "<string>",
          "formattedAddress": "<string>"
        }
      }
    ],
    "registeredAddress": {
      "line1": "<string>",
      "line2": "<string>",
      "city": "<string>",
      "postalCode": "01000",
      "country": "MEX"
    },
    "principalPlaceOfBusinessAddress": {
      "line1": "<string>",
      "line2": "<string>",
      "city": "<string>",
      "postalCode": "01000",
      "country": "MEX"
    },
    "businessWebsiteUrl": "https://example.com",
    "validEmailDomains": ["example.com"],
    "lineOfBusiness": "PROFESSIONAL_SERVICES",
    "dateOfIncorporation": "2015-06-01",
    "ddq": {
      "cardAuthorities": [
        {
          "fullName": "<string>",
          "role": "<string>"
        }
      ],
      "expectedSpendProfile": {
        "spendBuckets": [
          {
            "name": "<string>",
            "expectedSpendUsd": 25000,
            "jurisdictionIso": "<string>",
            "txnPattern": {
              "frequency": "monthly",
              "avgTicketUsd": 2000,
              "peakDays": ["MON"]
            }
          }
        ]
      },
      "numberOfEmployees": 100
    },
    "edd": {
      "sourceOfFundsDeclaration": "<string>",
      "sourceOfWealthDeclaration": "<string>"
    }
  },
  "uboEntities": [
    {
      "externalUserId": "<string>",
      "entityId": "<uuid>",
      "ownershipPct": 100
    }
  ]
}

Key Output

Parameter NameTypeDescription
submittedRequirementIdstringIdentifies the submission record created by this call
payloadobjectShows the stored KYB payload after validation
uboEntities.entityIduuidIdentifies the individual entity for the document upload call
uboEntities.externalUserIdstringIdentifies the owner through the client supplied reference

Step 4: Amend KYB Pack

Amend the stored KYB payload while the case remains editable. Use this step to correct a stored value.


Call the Amend KYB Pack Endpoint

Use PATCH /entity/entityId/ukyb to update part of the stored KYB payload.


Sample Request (cURL)

curl --request PATCH \
  --url https://sandbox-compliance.api.reap.global/entity/entityId/ukyb \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --header 'x-reap-api-key: ********' \
  --data '{
    "edd": {
      "sourceOfFundsDeclaration": "<string>"
    }
  }'
Parameter NameTypeDescription
entityIdstringIdentifies the business entity that holds the stored payload
edd.sourceOfFundsDeclarationstringDefines the updated source of funds statement

Sample Response

{
  "submittedRequirementId": "<string>",
  "payload": {
    "legalBusinessName": "<string>",
    "legalFormOfCompany": "PRIVATE_LIMITED",
    "businessRegistrationNumber": "<string>",
    "uboDeclaration": [
      {
        "externalUserId": "<string>",
        "ownershipPct": 100,
        "identity": {
          "firstName": "<string>",
          "middleName": "<string>",
          "lastName": "<string>",
          "fullName": "<string>",
          "dob": "1992-04-15",
          "nationality": "MEX"
        },
        "document": [
          {
            "documentCategory": "IDV",
            "type": "PASSPORT",
            "number": "A12345678",
            "country": "MEX",
            "issuingDate": "2020-01-10",
            "expiryDate": "2030-01-09"
          }
        ],
        "address": {
          "country": "MEX",
          "postCode": "01000",
          "town": "<string>",
          "street": "<string>",
          "state": "<string>",
          "buildingNumber": "<string>",
          "formattedAddress": "<string>"
        }
      }
    ],
    "registeredAddress": {
      "line1": "<string>",
      "line2": "<string>",
      "city": "<string>",
      "postalCode": "01000",
      "country": "MEX"
    },
    "principalPlaceOfBusinessAddress": {
      "line1": "<string>",
      "line2": "<string>",
      "city": "<string>",
      "postalCode": "01000",
      "country": "MEX"
    },
    "businessWebsiteUrl": "https://example.com",
    "validEmailDomains": ["example.com"],
    "lineOfBusiness": "PROFESSIONAL_SERVICES",
    "dateOfIncorporation": "2015-06-01",
    "ddq": {
      "cardAuthorities": [
        {
          "fullName": "<string>",
          "role": "<string>"
        }
      ],
      "expectedSpendProfile": {
        "spendBuckets": [
          {
            "name": "<string>",
            "expectedSpendUsd": 25000,
            "jurisdictionIso": "<string>",
            "txnPattern": {
              "frequency": "monthly",
              "avgTicketUsd": 2000,
              "peakDays": ["MON"]
            }
          }
        ]
      },
      "numberOfEmployees": 100
    },
    "edd": {
      "sourceOfFundsDeclaration": "<string>",
      "sourceOfWealthDeclaration": "<string>"
    }
  },
  "uboEntities": [
    {
      "externalUserId": "<string>",
      "entityId": "<uuid>",
      "ownershipPct": 100
    }
  ]
}

Key Output

Parameter NameTypeDescription
submittedRequirementIdstringIdentifies the submission record created by this amendment
payloadobjectShows the complete stored payload after the merge

Step 5: Upload KYB Documents

Upload the files that each required document requirement expects. Use this step once for every required record, because one call carries one requirement.


Call the Upload KYB Documents Endpoint

Use POST /entity/entityId/ukyb/documents to store the files that satisfy one document requirement.


i) Sample Request (cURL): Company Document

curl --request POST \
  --url https://sandbox-compliance.api.reap.global/entity/entityId/ukyb/documents \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --header 'x-reap-api-key: ********' \
  --form 'documentType=certificate-of-incorporation' \
  --form 'files=@/path/to/certificate-of-incorporation.pdf'

Key Input

Parameter NameTypeDescription
entityIdstringIdentifies the business entity that the company record belongs to
documentTypestringSpecifies the one company requirement that the files satisfy
filesarrayProvides the files stored against the requirement

i) Sample Response

{
  "submittedRequirementId": "<string>",
  "documentType": "certificate-of-incorporation",
  "files": [
    {
      "fileId": "<string>",
      "fileName": "certificate-of-incorporation.pdf"
    }
  ]
}

Key Output

Parameter NameTypeDescription
submittedRequirementIdstringIdentifies the submission record that now holds the files
documentTypestringShows the requirement that the files were filed under
files.fileIdstringIdentifies each stored file
ℹ️

The same request repeats for company-profile and shareholding-chart, because one call carries one documentType. A company requirement appends across uploads, so a later call adds files rather than replacing the stored set.


ii) Sample Request (cURL): Beneficial Owner Identity Document

curl --request POST \
  --url https://sandbox-compliance.api.reap.global/entity/entityId/ukyb/documents \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --header 'x-reap-api-key: ********' \
  --form 'documentType=ubo-kyc' \
  --form 'uboDocumentType=PASSPORT' \
  --form 'files=@/path/to/passport-front.jpg'

Key Input

Parameter NameTypeDescription
entityIdstringIdentifies the individual entity
documentTypestringSpecifies the identity requirement that the files satisfy
uboDocumentTypestringSpecifies the kind of identity document being uploaded
filesarrayProvides the identity files in front and back order

Sample Response

{
  "submittedRequirementId": "<string>",
  "documentType": "ubo-kyc",
  "files": [
    {
      "fileId": "<string>",
      "fileName": "passport-front.jpg"
    }
  ]
}

Key Output

Parameter NameTypeDescription
submittedRequirementIdstringIdentifies the submission record that now holds the identity files
documentTypestringShows the requirement that the files were filed under
files.fileIdstringIdentifies each stored file in upload order

Step 6: Submit KYB For Review

Close the case and send it to compliance review. Use this step once the stored payload and the required documents are complete.


Call the Submit KYB For Review Endpoint

Use POST /entity/entityId/ukyb/submit to close the case and queue it for compliance review.

ℹ️

The call carries no body because the pack and the documents are already stored. Completeness checks the presence of each required requirement rather than the approval of any document.


Sample Request (cURL)

curl --request POST \
  --url https://sandbox-compliance.api.reap.global/entity/entityId/ukyb/submit \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --header 'x-reap-api-key: ********' \

Key Input

Parameter NameTypeDescription
entityIdstringIdentifies the business entity whose case is submitted

Sample Response

{
  "entityId": "<string>",
  "submittedAt": "2026-01-01T00:00:00Z"
}

Key Output

Parameter NameTypeDescription
entityIdstringIdentifies the business entity whose KYB was submitted
submittedAtstringShows when the submission was accepted
⚠️

The payload is locked from this point, so further pack and document calls are rejected. To resubmit the case, the client contacts the program manager.


Scenarios

Scenario: Straight Through Onboarding

  • The client registers the destination with POST /notification before it opens the first case
  • The client creates the record that owns the case with POST /entity and keeps the returned identifier for every later call
  • The client stores the complete pack with POST /entity/entityId/ukyb and keeps the individual entity returned for each declared owner
  • The client files the three company records against the business entity with three calls to POST /entity/entityId/ukyb/documents
  • The client files the identity document of each declared owner against the individual entity of that owner with POST /entity/entityId/ukyb/documents
  • The client confirms that every required requirement holds a file and closes the case with POST /entity/entityId/ukyb/submit
  • The client verifies the signature on the delivered event and records the reported status against the business entity

Scenario: Case Amendment Before Submission

  • The client corrects a stored value with PATCH /entity/entityId/ukyb and compares the returned payload against the intended values
  • The client uploads the identity document of every owner again with POST /entity/entityId/ukyb/documents against the new individual entity
  • The client confirms that the case still accepts edits and closes it with POST /entity/entityId/ukyb/submit
  • The client verifies the signature on the delivered event and records the reported status against the business entity

Scenario: Incomplete File Uploads

  • The client uploads part of the required files with POST /entity/entityId/ukyb/documents
  • The client calls POST /entity/entityId/ukyb/submit
  • The client verifies the signature on the delivered event and records the reported status against the business entity

Common Errors

ErrorCauseResolution
INCOMPLETE_KYBThe case reaches submission while a required value or a required document is missingThe stored pack and every required document are in place before the case closes

TL;DR

  • Step 1 covers the status feed, where POST /notification registers the destination that receives each decision event
  • Step 2 opens the case record, where POST /entity creates the business entity that every later call addresses
  • Steps 3 to 4 cover the KYB pack, where POST /entity/entityId/ukyb stores the complete pack and creates an individual entity for each declared owner and PATCH /entity/entityId/ukyb amends the stored payload while the case remains editable
  • Step 5 covers document collection, where POST /entity/entityId/ukyb/documents files the three required company records against the business entity and one required identity record against the individual entity of each declared owner
  • Step 6 covers case closure, where POST /entity/entityId/ukyb/submit checks completeness, locks the stored payload, and queues the case for compliance review

Did this page help you?