Skip to content

[Ready] Implement and unify KYC/B processes via API. - #1318

Open
gianfra-t wants to merge 30 commits into
stagingfrom
streamline-kyc-kyb
Open

[Ready] Implement and unify KYC/B processes via API.#1318
gianfra-t wants to merge 30 commits into
stagingfrom
streamline-kyc-kyb

Conversation

@gianfra-t

@gianfra-t gianfra-t commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

API-driven, provider-specific KYC/KYB onboarding

Adds provider-aware onboarding discovery and expands API-driven KYC/KYB support while preserving the existing provider-specific endpoint families.

Changes

  • Adds public onboarding-requirements discovery for supported Avenia and AlfredPay country/customer-type combinations.
  • Publishes ordered API, direct-upload, and provider-hosted workflow steps.
  • Keeps OpenAPI authoritative for request schemas while discovery supplies validated fixed and derived workflow bindings.
  • Adds API-driven Avenia Level 1 KYB for company documents, UBO registration, submission, reconciliation, and status tracking.
  • Preserves the existing Avenia hosted Web SDK flow rather than replacing it.
  • Extends managed-profile authorization to supported provider operations.
  • Adds typed AlfredPay status lookup for individual and business customers.
  • Retains recoverable BRL ramps for subsequent polling and recovery attempts.
  • Restricts client-controlled ramp state updates to approved fields.

Managed-profile pricing

Managed children inherit the controlling manager’s active partner-pricing assignment when the child has no active assignment.

Pricing precedence is:

  1. The child profile’s active assignment.
  2. The controlling manager’s active assignment.
  3. Default Vortex pricing.

This applies to delegated manager requests and requests authenticated directly as the managed child. It can change quote fees and pricing attribution for existing managed children that do not have their own assignment.

Compatibility

  • Existing provider-specific endpoints and request contracts remain available.
  • Existing Avenia and AlfredPay hosted flows remain available.
  • No provider-neutral execution endpoint family is introduced.
  • OpenAPI remains authoritative for complete request, response, and error schemas.

Testing

  • Unit and integration coverage for Avenia KYB orchestration, ownership, reconciliation, and status handling.
  • Onboarding discovery and OpenAPI synchronization checks.
  • Managed-profile pricing precedence and quote/ramp lifecycle coverage.
  • AlfredPay customer-type validation and typed status lookup.
  • BRL ramp recovery and client-update allowlist coverage.

@netlify

netlify Bot commented Aug 5, 2026

Copy link
Copy Markdown

Deploy Preview for vortex-sandbox ready!

Name Link
🔨 Latest commit 5c8593b
🔍 Latest deploy log https://app.netlify.com/projects/vortex-sandbox/deploys/6a7f947bc7611f0007a826f4
😎 Deploy Preview https://deploy-preview-1318--vortex-sandbox.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@gianfra-t gianfra-t changed the title Streamline kyc kyb [WIP] Implement and unify KYC/B processes via API. Aug 5, 2026
ebma and others added 20 commits August 6, 2026 10:42
# Conflicts:
#	docs/proposal-headless-profiles-and-pricing-plans.md
# Conflicts:
#	apps/api/src/api/controllers/brla.controller.test.ts
#	apps/api/src/api/controllers/brla.controller.ts
#	docs/security-spec/05-integrations/brla.md
#	packages/shared/src/services/brla/brlaApiService.test.ts
#	packages/shared/src/services/brla/brlaApiService.ts
#	packages/shared/src/services/brla/mappings.ts
#	packages/shared/src/services/brla/schemas.test.ts
#	packages/shared/src/services/brla/schemas.ts
#	packages/shared/src/services/brla/types.ts
# Conflicts:
#	docs/api/openapi/vortex.openapi.d.ts
#	docs/api/openapi/vortex.openapi.json
#	docs/api/pages/10-sandbox.md
#	docs/api/scripts/check-openapi.ts
#	docs/security-spec/05-integrations/alfredpay.md
#	docs/security-spec/05-integrations/brla.md
Bring the managed-profile idempotency ledger (runFinancialOperation, the
064 profile-scope migration) and the associated infrastructure into the
streamlined KYC/KYB branch. createSubaccount now claims an exactly-once
financial operation keyed on the tax-reference hash, keeping HEAD's Avenia
attempt-state simplification while removing the overwrite-on-retry hazard.

Resolve conflicts in favor of HEAD's Avenia simplification (no submission
state machine) plus the merged idempotency block. Regenerate the
wire-contract snapshot for the now-required record-attempt quoteId, and fix
check-openapi to resolve the record-attempt request-body $ref before
asserting its required fields.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Avenia omits resultMessage and retryable until an attempt settles, so a
PENDING poll parsed by aveniaAttemptSchema raised a ZodError that surfaced
to the client as a 502 and could permanently block hosted KYB resume.
Make both fields optional in the schema and the KycAttempt /
AveniaVerificationAttempt types; every consumer already reads them
optional-safely.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
recordInitialKycAttempt only null-checked quoteId and never used it, so any
authenticated caller could plant a Consulted provider_customers marker on
another profile's CPF/CNPJ — a started row that then blocks the rightful
owner's createSubaccount. Assert the caller owns the referenced quote and
that it is a Brazil corridor (BRL on either leg) before persisting the
marker. Update the F-064 security-spec entry to record quoteId as an
authorization input.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@gianfra-t gianfra-t changed the title [WIP] Implement and unify KYC/B processes via API. [Ready] Implement and unify KYC/B processes via API. Aug 12, 2026
@gianfra-t
gianfra-t requested a balanced review from Copilot August 12, 2026 20:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds API-driven Avenia KYB and public onboarding discovery, while also bundling managed-profile pricing and ramp-recovery changes.

Changes:

  • Adds Avenia document, UBO, submission, reconciliation, and status APIs.
  • Publishes provider-specific onboarding requirements and OpenAPI validation.
  • Changes managed-profile pricing and BRL ramp recovery behavior.

Reviewed changes

Copilot reviewed 50 out of 52 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
packages/shared/src/services/brla/types.ts Adds Avenia KYB types.
packages/shared/src/services/brla/schemas.ts Validates Avenia responses.
packages/shared/src/services/brla/schemas.test.ts Tests response schemas.
packages/shared/src/services/brla/mappings.ts Adds provider endpoint mappings.
packages/shared/src/services/brla/brlaApiService.ts Implements KYB provider calls.
packages/shared/src/services/brla/brlaApiService.test.ts Tests provider mappings.
packages/shared/src/endpoints/onboarding-requirements.endpoints.ts Defines discovery metadata.
packages/shared/src/endpoints/onboarding-requirements.endpoints.test.ts Tests discovery flows.
packages/shared/src/endpoints/index.ts Exports discovery contracts.
packages/shared/src/endpoints/brla.endpoints.ts Makes KYC result optional.
packages/shared/src/endpoints/alfredpay.endpoints.ts Adds status type selector.
docs/security-spec/07-operations/api-surface.md Documents public discovery.
docs/security-spec/05-integrations/brla.md Updates Avenia invariants.
docs/security-spec/05-integrations/alfredpay.md Documents typed status lookup.
docs/security-spec/03-ramp-engine/quote-lifecycle.md Documents manager pricing.
docs/security-spec/03-ramp-engine/profile-partner-pricing.md Defines pricing precedence.
docs/README.md Indexes the proposal.
docs/proposal-api-driven-kyc-kyb.md Proposes API-driven verification.
docs/api/wire-contract.snapshot.md Updates generated contracts.
docs/api/scripts/check-openapi.ts Checks discovery/OpenAPI consistency.
docs/api/pages/10-sandbox.md Improves wallet guidance.
docs/api/pages/06-quotes-and-pricing.md Documents inherited pricing.
docs/api/pages/03-authentication-and-partner-keys.md Documents managed pricing precedence.
docs/api/apidog/page-manifest.json Publishes new API pages.
docs/adr-0003-managed-headless-profiles.md Updates pricing decision.
apps/api/src/tests/managed-profile-quote-ramp-lifecycle.integration.test.ts Tests inherited pricing.
apps/api/src/tests/http-surface.invariants.test.ts Tests public discovery.
apps/api/src/tests/contracts/avenia.contract.test.ts Notes missing live coverage.
apps/api/src/api/workers/unhandled-payment.worker.ts Retains recoverable ramps.
apps/api/src/api/workers/unhandled-payment.worker.test.ts Tests repeated recovery.
apps/api/src/api/services/ramp/ramp.service.update-additional-data.test.ts Tests state-field restrictions.
apps/api/src/api/services/ramp/ramp.service.ts Allowlists client state updates.
apps/api/src/api/services/quote/index.ts Carries manager context.
apps/api/src/api/services/quote/core/types.ts Extends pricing context types.
apps/api/src/api/services/quote/core/quote-context.ts Accepts manager context.
apps/api/src/api/services/quote/core/partner-resolution.ts Adds manager pricing fallback.
apps/api/src/api/services/quote/core/partner-resolution.test.ts Tests pricing precedence.
apps/api/src/api/services/avenia/avenia-kyb.service.ts Adds KYB ownership helpers.
apps/api/src/api/services/avenia/avenia-customer.service.ts Reformats case updates.
apps/api/src/api/routes/v1/onboarding.route.ts Exposes discovery route.
apps/api/src/api/routes/v1/onboarding-requirements.route.test.ts Tests unauthenticated access.
apps/api/src/api/routes/v1/brla.route.ts Registers KYB routes.
apps/api/src/api/middlewares/validators.ts Validates KYB payloads.
apps/api/src/api/middlewares/validators.test.ts Tests KYB validation.
apps/api/src/api/controllers/quote.controller.ts Passes manager pricing context.
apps/api/src/api/controllers/onboarding.controller.ts Serves discovery metadata.
apps/api/src/api/controllers/onboarding-requirements.controller.test.ts Tests discovery responses.
apps/api/src/api/controllers/brla.controller.ts Implements API KYB orchestration.
apps/api/src/api/controllers/brla.controller.test.ts Tests KYB and ownership behavior.
apps/api/src/api/controllers/alfredpay.controller.ts Supports typed status lookup.
Suppressed comments (2)

apps/api/src/api/controllers/brla.controller.ts:897

  • This reconciliation blindly rewrites the case from a provider-list snapshot. If a concurrent status poll observes the same attempt as completed and persists approval/rejection after this list call but before this update, reconciliation can overwrite that terminal state back to pending/in-review and clear lifecycle fields. Lock/CAS the current nonterminal case and enforce monotonic external-status transitions, as the polling path already does.
    await kycCase.update(
      {
        approvedAt: null,
        failureReasons: [],
        providerCaseId: attempt.id,

apps/api/src/api/controllers/brla.controller.ts:976

  • UBO creation is not retry-safe. If Avenia creates the UBO but the response is lost (the shared client has a 30-second timeout), retrying this endpoint issues another POST with no idempotency key, durable operation claim, or reconciliation path, potentially creating duplicate beneficial-owner records and leaving the client without the original ID. Add an idempotent operation identifier or persist/reconcile the provider result before allowing retries.
    const response = await brlaApiService.createUbo(req.body, subAccountId);
    res.status(httpStatus.CREATED).json(response);

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread apps/api/src/api/controllers/brla.controller.ts Outdated
Comment thread apps/api/src/api/services/avenia/avenia-kyb.service.ts Outdated
Comment thread apps/api/src/api/controllers/alfredpay.controller.ts
Comment thread packages/shared/src/endpoints/onboarding-requirements.endpoints.ts
Comment thread docs/proposal-api-driven-kyc-kyb.md
Comment thread apps/api/src/api/services/quote/core/partner-resolution.ts
Base automatically changed from managed-profiles to staging August 13, 2026 14:58
@netlify

netlify Bot commented Aug 13, 2026

Copy link
Copy Markdown

Deploy Preview for vrtx-dashboard canceled.

Name Link
🔨 Latest commit 5c8593b
🔍 Latest deploy log https://app.netlify.com/projects/vrtx-dashboard/deploys/6a7f947b5f5dc700085b91cd

@netlify

netlify Bot commented Aug 13, 2026

Copy link
Copy Markdown

Deploy Preview for vortexfi ready!

Name Link
🔨 Latest commit 5c8593b
🔍 Latest deploy log https://app.netlify.com/projects/vortexfi/deploys/6a7f947b569d640008df0bae
😎 Deploy Preview https://deploy-preview-1318--vortexfi.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 82 out of 84 changed files in this pull request and generated 2 comments.

Suppressed comments (4)

packages/shared/src/services/brla/brlaApiService.ts:451

  • API KYB submission has the same PII exposure as standard KYC (company identity, tax number, address, document IDs and financial profile), but this call does not enable sensitive-body mode. The generic client logs the payload and includes provider response text in thrown errors. Pass sensitiveBody: true and cover both request logging and echoed provider errors in the client tests.
    packages/shared/src/endpoints/alfredpay.endpoints.ts:35
  • Moving type to the status request does not require removing it from this existing exported request contract. Typed clients that still construct the prior redirect-link query now fail excess-property checks, contrary to the compatibility guarantee. Retain the property as deprecated/ignored so the runtime behavior can remain unchanged without a source break.
    apps/api/src/api/controllers/brla.controller.ts:1118
  • A timeout or lost response from this POST leaves no durable submission claim. On retry, if Avenia has accepted the attempt but its list endpoint has not exposed it yet, preflight sees zero active attempts and sends the KYB payload again. Persist a prepared/submitted/ambiguous claim before the provider call, and allow retries to reconcile that claim without repeating the POST, as the individual KYC flow does.
    let response: KycLevel1Response;
    try {
      response = await brlaApiService.submitKybLevel1(req.body, subAccountId);
    } catch (error) {
      if (!(error instanceof BrlaApiError) || error.status !== httpStatus.CONFLICT) {
        throw error;

packages/shared/src/endpoints/brla.endpoints.ts:47

  • The PR states that existing request contracts remain available, but removing quoteId and sessionId from this exported shared wire type is source-breaking for typed clients that still send the legacy query shape, even though the server can ignore those fields. Keep them as deprecated optional properties while making only taxId required.

Comment on lines +296 to +298
public async createUbo(payload: AveniaUboPayload, subAccountId: string): Promise<AveniaUboResponse> {
const query = `subAccountId=${encodeURIComponent(subAccountId)}`;
return aveniaUboResponseSchema.parse(await this.sendRequest(Endpoint.Ubos, "POST", query, payload));
Comment on lines +1128 to +1132
const now = new Date();
await sequelize.transaction(async transaction => {
await record.update(
{
lastFailureReasons: [],
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants