1. Documentation
Vortex
  • Documentation
    • Overview
    • Quick Start With The SDK
    • Authentication And API Keys
    • Ramp Lifecycle
    • Ephemeral Key Custody
    • Quotes And Pricing
    • Webhooks
    • Widget Integration
    • Fiat Corridors
    • Sandbox
    • Production Checklist
    • KYB Deep Link
    • Managed Profiles
    • Custom UI Integration
    • AI Agent Integration
  • API Endpoints
    • Vortex Widget
      • Create widget session
    • Quotes
      • Create a new quote
      • Get existing quote
      • Create a quote for the best network
    • Ramp
      • Get ramp status
      • Get ramp error logs
      • Get ramp history for wallet address
      • Register new ramp process
      • Start ramp process
      • Get authenticated user ramp history
      • Update ramp process
    • Reference Data
      • Supported Countries
      • Supported Cryptocurrencies
      • Supported Fiat Currencies
      • Supported Payment Methods
    • Public Key
      • Public Key
    • Webhooks
      • Register Webhook
      • Delete Webhook
    • Account Management
      • Create user or retry KYC
      • Get user's KYC status
      • Get selfie liveness URL
      • Get KYC document upload URLs
      • Get KYC document upload URLs
      • Get user information
      • Get user's remaining transaction limits
      • Submit KYC level 1 data
      • Validate Pix key
      • Create user or retry KYC
      • Get user's KYC status
      • Get selfie liveness URL
      • Get user information
      • Get user's remaining transaction limits
      • Submit KYC level 1 data
      • Validate PIX key
      • List fiat accounts
      • Create a fiat account
      • Delete a fiat account
      • Get user ramp limits
      • Get sanitized ramp eligibility
    • Authentication
      • List the user's API keys
      • Create a user-linked API key pair
      • Revoke an API key
      • Request an email OTP
      • Verify an email OTP
      • List API credentials
      • Create an API credential
      • Revoke an API credential
    • KYC and KYB
      • Get KYB attempt status
      • Create KYB document
      • Get KYB document
      • Submit API-driven KYB
      • Start hosted KYB
      • Create KYB UBO
      • Import an individual KYC token
      • Record an initial KYC attempt
      • Get customer status
      • Create a business customer
      • Create an individual customer
      • Find KYB submission details
      • Get a KYB redirect link
      • Get a KYC redirect link
      • Get KYC or KYB status
      • Mark a redirect finished
      • Mark a redirect opened
      • Retry KYC or KYB
      • Send a KYB submission
      • Send a KYC submission
      • Upload a KYB file
      • Submit KYB information
      • Upload a related-person KYB file
      • Upload a KYC file
      • Submit KYC information
      • Select active customer entity
      • Discover KYC or KYB requirements
      • Get aggregate onboarding status
    • Managed Profiles
      • List managed profiles
      • Create a managed profile
      • Delete a managed profile
      • Get a managed profile
      • List a managed profile's API credentials
      • Create a managed profile API credential
      • Revoke a managed profile API credential
    • Schemas
      • AccountMeta
      • AveniaDocumentType
      • ApiCredential
      • AveniaKYCDataUploadRequest
      • ApiCredentialErrorResponse
      • AveniaKYCDataUploadResponse
      • ApiCredentialManagedSelectorErrorResponse
      • BrlaAddress
      • ApiValidationErrorResponse
      • BrlaErrorResponse
      • BrAddress
      • BrlaGetSelfieLivenessUrlResponse
      • BrDocumentType
      • BrlaValidatePixKeyResponse
      • BrErrorResponse
      • CleanupPhase
      • BrGetSelfieLivenessUrlResponse
      • CountryCode
      • BrImportKycTokenErrorResponse
      • CreateBestQuoteRequest
      • BrImportKycTokenRequest
      • CreateQuoteRequest
      • BrImportKycTokenResponse
      • BrKYCDataUploadRequest
      • BrKYCDataUploadResponse
      • DestinationType
      • BrKybAttemptStatusResponse
      • BrKybDocumentRequest
      • ErrorResponse
      • BrKybDocumentResponse
      • FiatToken
      • BrKybDocumentUploadResponse
      • BrKybHostedResponse
      • GetRampErrorLogsResponse
      • BrKybLevel1Payload
      • GetRampHistoryResponse
      • BrManagedBadRequestResponse
      • BrUboControlRole
      • BrUboPayload
      • BrUboResponse
      • GetWidgetUrlLocked
      • BrValidatePixKeyResponse
      • GetWidgetUrlRefresh
      • KYCDataUploadFileFiles
      • KYCDocType
      • CreateApiCredentialRequest
      • KycLevel1Payload
      • CreateApiCredentialResponse
      • KycLevel1Response
      • ListUserApiKeysResponse
      • CreateManagedProfileRequest
      • Networks
      • CreateSubaccountRequest
      • OnChainToken
      • CreateSubaccountResponse
      • PaymentData
      • PaymentMethod
      • DocumentUploadEntry
      • PresignedTx
      • QuoteResponse
      • DomesticAddFiatAccountRequest
      • RampCurrency
      • DomesticCountry
      • RampDirection
      • DomesticCountryAndCustomerTypeRequest
      • RampErrorLog
      • DomesticCountryRequest
      • RampPhase
      • DomesticCreateCustomerRequest
      • RampProcess
      • DomesticCreateCustomerResponse
      • RegisterRampRequest
      • DomesticCreateFiatAccountResponse
      • SimpleStatus
      • DomesticCustomerType
      • StartKYC2Request
      • DomesticErrorResponse
      • StartKYC2Response
      • DomesticFiatAccount
      • StartRampRequest
      • DomesticFiatAccountType
      • TaxIdType
      • DomesticKybBusinessSummary
      • TriggerOfframpRequest
      • DomesticKybDetailsResponse
      • TriggerOfframpResponse
      • DomesticKybFileUploadRequest
      • UnsignedTx
      • DomesticKybRelatedPerson
      • DomesticKybRelatedPersonFileUploadRequest
      • UserApiKeyErrorResponse
      • DomesticKycFileUploadRequest
      • UserApiKeyPairResponse
      • DomesticKycStatusResponse
      • ValidatePixKeyResponse
      • DomesticManagedBadRequestResponse
      • DomesticRedirectLinkResponse
      • DomesticRedirectNotificationRequest
      • DomesticRelatedPersonFileUploadRequest
      • DomesticRetryRequest
      • DomesticRetryResponse
      • DomesticSendSubmissionRequest
      • DomesticStatus
      • DomesticStatusResponse
      • DomesticSubmissionResponse
      • DomesticSubmitKybInformationRequest
      • DomesticSubmitKycInformationRequest
      • DomesticSuccessResponse
      • DomesticValidationBadRequestResponse
      • ErrorManagedSelectorResponse
      • FlatErrorResponse
      • FlatManagedSelectorErrorResponse
      • GetKycStatusResponse
      • GetRampHistoryTransaction
      • GetUserLimitsRequest
      • GetUserLimitsResponse
      • GetUserRemainingLimitResponse
      • GetUserResponse
      • KybAttemptStatusResponse
      • KybLevel1Response
      • ListApiCredentialsResponse
      • ListManagedProfilesResponse
      • MalformedJsonErrorResponse
      • LivenessDocumentEntry
      • ManagedProfile
      • ManagedProfileErrorResponse
      • ManagedProfilePagination
      • ManagedProfileResponse
      • ManagedProfileManagerPolicy
      • ManagedSelectorErrorResponse
      • OnboardingApiErrorResponse
      • OnboardingDocumentRequirement
      • OnboardingRequirementStep
      • OnboardingRequirementsErrorResponse
      • OnboardingRequirementsResponse
      • OnboardingStatusErrorResponse
      • OnboardingStatusResponse
      • PayloadTooLargeErrorResponse
      • RampInfoResponse
      • RecordInitialKycAttemptRequest
      • SelectActiveCustomerEntityRequest
      • SelectActiveCustomerEntityResponse
      • SubmitInformationResponse
      • SubmitKybInformationRequest
      • SubmitKycInformationRequest
      • SuccessResponse
      • UpdateRampRequest
      • UserLimit
      • UserLimitPeriod
  1. Documentation

Authentication And API Keys

Vortex issues one API credential with two values for one profile subject:

  • pk_live_* / pk_test_* is the public value. Send it as X-Public-Key for quote/widget attribution and approved low-sensitivity reads. It may be used in browser code.
  • sk_live_* / sk_test_* is the secret value. Send it as X-API-Key for sensitive or state-changing operations. It must remain on a trusted server.

Both values share one immutable credential ID, subject profile, optional partner, environment, expiry, and revocation lifecycle. If a request sends both values, they must belong to the same credential or Vortex returns 403 CREDENTIAL_MISMATCH.

Capability Matrix

TaskPublic valueSecret valueSupabase Bearer
Quote/widget attributionYesYesYes
Sanitized GET /v1/ramp-infoYesYesNo
Exact limits and provider-account readsNoYesYes
Ramp register/update/start/status/history/errorsNoYesYes
Act for an authorized managed childNoYesYes
Manage a directly owned child's credentialsNoYesYes
Import an individual-KYC share token (BR)NoYesYes
Webhook management (non-managed subjects only)NoYesNo
Profile-managed credential lifecycleNoNoYes

GET /v1/ramp-info requires X-Public-Key or X-API-Key; a Supabase Bearer session does not authorize this endpoint. It returns only per-corridor kycStatus, canBuy, and canSell. A manager secret may supply X-Managed-Profile-Id; public keys may not. It accepts no body/query profile or user selector and does not expose PII, provider identifiers, KYC failure reasons, account details, ramp history, or exact limits.

Browser Origin Approval

Vortex accepts browser requests only from origins it has explicitly approved. Every request a browser makes to the API — the browser build of @vortexfi/sdk, a fetch from your own front end, or POST /v1/session/create called from page code — is refused by CORS unless your exact origin is on the allowlist. Server-to-server calls are unaffected.

To have an origin approved, email support@vortexfinance.co with:

  • each origin exactly as the browser sends it, including scheme and any non-default port (for example https://app.example.com or https://checkout.example.com:8443);
  • whether it is for sandbox, production, or both.

Entries are exact-match and wildcards are never accepted, so every subdomain, preview domain, and development host that calls the API must be listed individually. Request approval before you integrate: without it every browser call fails at the CORS preflight, which surfaces as a browser network error rather than a Vortex error code.

Subject And Partner Binding

Every credential authenticates exactly one Vortex profile. A profile-managed credential has no partner and is managed by its signed-in subject. A partner-managed credential has an optional partner attribution but still authenticates only its bound profile.

Ramp registration requires a real profile subject in every corridor. KYC and provider identity are derived from the authenticated profile unless the request uses the authorized managed-child flow below. For BRL, a supplied taxId is only a deprecated cross-check and must match the effective profile. A technical profile can operate only on provider/customer resources it actually owns.

Act For A Managed Child

Vortex may enable an authenticated profile as a managed-profile manager and assign its allowed corridors and, optionally, a narrower set of customer types. On supported child-oriented endpoints, that manager can select one directly managed headless child:

X-API-Key: sk_live_...
X-Managed-Profile-Id: 00000000-0000-0000-0000-000000000002

A Supabase Bearer session may replace the secret key. A public pk_* value cannot authenticate delegation. Vortex verifies the active manager, direct active child relationship, child's single active customer entity, allowed country, optional customer-type narrowing, and canonical country/type support for corridor-bound mutations. An omitted or null customer-type policy adds no restriction beyond the canonical corridor capability matrix; a configured non-empty list only narrows that matrix. The manager remains the authenticated actor; ownership, KYC/provider lookup, and ramp history resolve from the child subject. Quote pricing uses the child's active profile assignment when present, otherwise the controlling manager profile's active assignment, then default Vortex pricing. This precedence is identical for manager-delegated requests and direct child credentials.

The header is supported for quote creation; ramp registration, update, start, status, history, and errors; exact limits and sanitized ramp info; aggregate onboarding status; BR customer/KYC operations; customer creation, KYC/KYB, and fiat-account operations on the AR, CO, MX, and US corridors; and sender-side recipient operations. Sender-side recipient operations are invite creation, recipient and pending-invitation listing, invitation archive/unarchive, recipient relationship updates, and recipient eligibility reads. These recipient operations currently require a Supabase Bearer session; an sk_* key does not authorize them. Invite preview and acceptance remain invitee-scoped and do not support X-Managed-Profile-Id; a headless managed child cannot authenticate as an invitee or accept an invitation. Corridor removal blocks mutations and disallowed exact-limit requests but not quote discovery or historical/status reads. The EUR corridor's flows remain bound to a verified login email and do not support managed children.

POST /v1/brl/kyc/import-token is a deliberate exception to direct child credential access. A controlling manager may call it with the manager's secret key or Supabase session plus X-Managed-Profile-Id, but a credential owned by the managed child is rejected with 403 MANAGED_PROFILE_ACCESS_DENIED, even without the selector. Direct non-managed profiles may import for themselves with their own secret key or session. Public keys and ownerless credentials cannot import. The legacy /v1/brla/kyc/import-token path remains an equivalent migration alias.

Authentication, direct-child rejection, and managed authorization run before strict validation of Idempotency-Key and the request body. An unauthenticated caller therefore receives an authentication error rather than learning whether a bearer-like personal-data transfer token or attestation is well formed. The request has no profile, user, CPF, subaccount, applicant, entity, or provider-customer selector in its body or query; identity is derived only from the authenticated effective profile.

Webhook registration and deletion do not support managed children. X-Managed-Profile-Id returns 400 MANAGED_PROFILE_UNSUPPORTED, and a direct child credential returns 403 MANAGED_PROFILE_ACCESS_DENIED. Managed-child integrations must poll the child-scoped ramp status/history endpoints. A manager credential without the selector remains manager-owned and therefore cannot register a webhook for a child-owned quote.

X-Managed-Profile-Id is only a selector. Supplying another manager's child, an inactive/deleted child, a child with an invalid entity layout, or a disallowed mutation corridor returns 403 MANAGED_PROFILE_ACCESS_DENIED.

Manage Headless Profiles

This section is the authoritative contract; for a step-by-step walkthrough with examples, see Managed Profiles.

An active manager may use its Supabase session or profile-bound secret credential on these endpoints:

EndpointPurpose
POST /v1/managed-profilesCreate an individual or business child from immutable externalSubjectId and provider contactEmail values
GET /v1/managed-profilesList children and the manager's current policy; defaults to active records with limit=50&offset=0
GET /v1/managed-profiles/:profileIdRead an owned active or deleted child
DELETE /v1/managed-profiles/:profileIdLogically delete an owned child and revoke its credentials
POST /v1/managed-profiles/:profileId/api-credentialsIssue a child-owned public/secret credential pair
GET /v1/managed-profiles/:profileId/api-credentialsList the child's credentials without secret values
DELETE /v1/managed-profiles/:profileId/api-credentials/:credentialIdRevoke one child credential

Creation is not tied to one corridor and may create only an individual or business child. Every later corridor-bound operation checks the manager's current corridors, optional customer-type narrowing, and Vortex's canonical corridor/type support. Tightening policy blocks later authorization decisions but does not cancel a request already authorized or background processing for a ramp that already started. POST returns 201 for a new child and 200 for an identical retry. A deleted external subject remains reserved and cannot create a replacement child. Deletion is idempotent (204), preserves compliance and financial history, and blocks new child activity.

Lists accept status=active|deleted|all, limit=1..100, and a non-negative offset; the default status is active. The response always includes manager.profileId, manager.allowedCorridors, and manager.allowedCustomerTypes alongside managedProfiles and pagination. This policy belongs to the manager and applies to every child; it is not copied onto individual managed profiles. Inactive managers lose create, list, read, delete, and delegated-operation access. Requests for another manager's child return 404 on lifecycle routes.

The child contact email is normalized and immutable, is unique among the manager's children, is used for provider customer creation, and never becomes a Supabase login identity. A deleted child's contact email remains reserved for that manager. Partners must supply an email identity they are authorized to use; uniqueness is not global across managers. A child-owned credential authenticates directly as that child without X-Managed-Profile-Id. Every use dynamically requires the active manager relationship; corridor-bound mutations and exact-limit reads use the controlling manager's current corridor/type policy. A direct child credential cannot select another managed child. Logical deletion immediately invalidates and revokes both halves.

Provision one genuine managed profile per individual or business when interactive signup is unavailable. Managed profiles are headless: they have no Supabase login, OTP, or later claiming lifecycle. Do not share dummy profiles between customers or infer a subject from a credential display name.

Secret Handling

Vortex stores only a SHA-256 digest and a safe lookup prefix for the secret value. The full secret is returned once when the credential is created. Store it immediately in a secret manager. Never place it in browser/mobile bundles, URLs, request bodies, screenshots, analytics, logs, support tickets, or source control.

Provision A Profile-Managed Credential

1. Request And Verify An OTP

POST /v1/auth/request-otp
Content-Type: application/json

{ "email": "user@example.com" }
POST /v1/auth/verify-otp
Content-Type: application/json

{ "email": "user@example.com", "token": "123456" }

Verification returns access_token, refresh_token, and user_id, creating the profile on first sign-in. POST /v1/auth/refresh accepts the refresh token when needed.

2. Create One Credential

POST /v1/api-credentials
Authorization: Bearer <access_token>
Content-Type: application/json

{
  "name": "production backend",
  "expiresAt": "2027-07-31T00:00:00.000Z"
}

Both fields are optional. Expiry defaults to one year, must be in the future, and cannot exceed two years. The response is one resource:

{
  "id": "00000000-0000-0000-0000-000000000000",
  "name": "production backend",
  "profileId": "00000000-0000-0000-0000-000000000001",
  "partnerId": null,
  "environment": "live",
  "publicKey": "pk_live_...",
  "secretKey": "sk_live_...",
  "secretKeyPrefix": "16-character safe prefix",
  "publicLastUsedAt": null,
  "secretLastUsedAt": null,
  "expiresAt": "2027-07-31T00:00:00.000Z",
  "revokedAt": null,
  "createdAt": "2026-07-31T00:00:00.000Z",
  "updatedAt": "2026-07-31T00:00:00.000Z"
}

The profile may have at most five active, non-expired credentials. Exceeding the cap returns 409 CREDENTIAL_LIMIT_REACHED. Sandbox issues *_test_*; production issues *_live_*.

3. Configure The SDK

const sdk = new VortexSdk({
  apiBaseUrl: "https://api.vortexfinance.co",
  publicKey: process.env.VORTEX_PUBLIC_KEY,
  secretKey: process.env.VORTEX_SECRET_KEY
});

A secret may be configured without a public value when only authenticated operations are needed. A public-only SDK can call getRampInfo() and create attributed quotes but cannot register or operate a ramp.

List And Revoke

  • GET /v1/api-credentials returns one item per credential. It includes the public value and safe secret prefix, never the secret value.
  • DELETE /v1/api-credentials/{credentialId} returns 204 and atomically revokes both values. It takes no request body and no second key ID.

Both endpoints require the subject's Supabase Bearer session. Secret API credentials cannot create or revoke other credentials.

Common Errors

CodeMeaning
INVALID_PUBLIC_KEYPublic value is unknown, expired, or revoked.
INVALID_SECRET_KEY / INVALID_API_KEYSecret value is malformed, unknown, expired, or revoked.
CREDENTIAL_MISMATCHPresented public/body/header and secret values do not identify one credential.
CREDENTIAL_LIMIT_REACHEDThe profile already has five active non-expired credentials.
CREDENTIAL_NOT_FOUNDCredential is missing, already revoked, or outside the authenticated manager's scope.
CREDENTIAL_SUBJECT_REQUIREDA valid profile subject was not supplied for partner-managed issuance.

Webhook Signing Key

GET /v1/public-key returns the RSA-PSS public key used to verify webhook signatures. It is unrelated to a pk_* API credential value.


Modified at 2026-09-08 09:47:51
Previous
Quick Start With The SDK
Next
Ramp Lifecycle
Built with