Customers
These are end-user customers, individuals or businesses that your product onboards onto the platform. They're scoped to your org. They are NOT the same thing as your org's own KYB onboarding, which lives under Orgs → KYB profile.
The surface is polymorphic. A Customer carries a type discriminator ("individual" or "business"). Profile data lives in a nested profile sub-object whose shape is picked by type (a KycProfile for individuals, a KybProfile for businesses). Every endpoint accepts either kind on the same URL and returns the right shape based on type.
All endpoints under /customers require auth, either an Api-Key: <key> (org-scoped, recommended) or Authorization: Bearer <access-token> (dashboard session). Customers are filtered to the org bound to the credential. Curl snippets assume $SEISMIC_ORCHESTRATION_URL and $SEISMIC_ORCHESTRATION_API_KEY, see Auth for the full model.
Endpoints
Lifecycle
POST /customers, create a customer (individual or business). Returns the new id and an auto-mintedkyc_link.GET /customers, list and filter customers, with cursor paging.GET /customers/:id, read a customer envelope:type,profile, and the inlinekyc_link.GET /customers/:id/kyc/profileis an alias.PUT /customers/:id/kyc/profile, upsert the profile body. Accepts partial drafts. Returns the same envelope.POST /customers/:id/kyc/submit, submit for verification (KYC for individuals, KYB for businesses).POST /customers/:id/kyc/sync-approvals, submit for any verification checks added since the customer was onboarded.GET /customers/:id/kyc/state, read the current verification state.GET /customers/:id/kyc/rfis, read the open requests for information on the verification.POST /customers/:id/kyc/resync, force a fresh sync of the cached verification verdict.
Hosted KYC link
Every customer carries a kyc_link inline on every read. Auto-minted at create-time. No separate endpoint needed to fetch it.
POST /customers/:id/kyc-link/rotate, overwrite the token in place after a suspected leak. Returns the new{ token, url }.
Documents
POST /customers/:id/kyc/documents, upload a supporting document.GET /customers/:id/kyc/documents, list documents.DELETE /customers/:id/kyc/documents/:doc_id, detach a document.
Orders
An order is the record created when a quote is accepted (see POST /quotes/:id/accept).
GET /customers/orders, list and filter orders across every customer.GET /customers/:id/orders, list one customer's orders.GET /customers/orders/:id, read a single order by id.POST /customers/orders/:id/cancel, cancel an order stillawaiting_fundsorpending.POST /customers/orders/:id/documents, submit the supporting document a held payment is waiting for.
Per-customer accounts
Live under Accounts: the create + read endpoints for a customer's fiat / crypto accounts all hang off /customers/:id/accounts/* but are documented in the Accounts section to keep this page focused on KYC/KYB.
Types
Customer
A polymorphic envelope returned by retrieve and update. The envelope carries the identity discriminator (type), the saved profile, and the inline kyc_link. Verification status (KYC for individuals, KYB for businesses) is not denormalized onto this record. Read it from GET /customers/:id/kyc/state instead.
| Field | Type | Notes |
|---|---|---|
type | "individual" | "business" | Discriminator. Picks the shape of profile (KYC vs KYB). |
profile | KycProfile | KybProfile | KycProfile when type === "individual", KybProfile when type === "business". |
kyc_link | HostedKycLink | Always present. Same field name for both kinds. The url path encodes the kind. Auto-minted at customer create. Rotate via POST /customers/:id/kyc-link/rotate. |
POST /customers returns the smaller { type, id, kyc_link } shape (no profile echoed back). Pass id back on every subsequent call.
Profile fields can be partially populated pre-submit. The wizard saves drafts via PUT /customers/:id/kyc/profile. Submit-time validation runs on POST /customers/:id/kyc/submit.
HostedKycLink
The partner-issued, Seismic-hosted KYC/KYB link. Every customer carries one inline on every read. No separate fetch endpoint exists. Partners share the url with their end-customer, who lands on a standalone wizard at /kyc-link/<kind>/<token> and fills in their own verification. The URL itself is the credential, so anyone with it can read and write that one customer's profile, upload documents, and submit. It cannot read other customers, mint other links, or act on the org.
| Field | Type | Notes |
|---|---|---|
token | string | Opaque, fixed-width (49 chars: klink_ + 43 base64url chars). Same plaintext embedded in url. Surfaced separately so partners running their own branded wizard can build URLs against their own frontend host. |
url | string | Absolute URL of the form <origin>/kyc-link/<kind>/<token> where <kind> is ind (individual), biz (business), or bi (business-individual). The origin is https://orchestration.seismic.systems on production and https://orchestration.seismictest.net on sandbox. Self-hosted deployments configure it via the APP_BASE_URL env var. Send this URL as-is to your end-customer. No client-side prefixing needed. |
No expiry, no revocation: if a token leaks, rotate it. Each rotation overwrites the token in place and 404s the previous URL.
Individual customer (type: "individual"): url carries the ind segment:
{
"token": "klink_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w",
"url": "https://orchestration.seismic.systems/kyc-link/ind/klink_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w"
}Business customer (type: "business"): same field name kyc_link, but url carries the biz segment:
{
"token": "klink_b9c8d7e6f5g4h3i2j1k0l9m8n7o6p5q4r3s2t1u0v9w8x",
"url": "https://orchestration.seismic.systems/kyc-link/biz/klink_b9c8d7e6f5g4h3i2j1k0l9m8n7o6p5q4r3s2t1u0v9w8x"
}Sandbox-issued links carry the same shape with the seismictest.net origin, e.g. https://orchestration.seismictest.net/kyc-link/ind/klink_….
The bi segment is reserved for business-individual links (B2B2C end-users of a business customer). The wizard for that flow isn't part of the public API surface yet.
Address
Shared shape used in profile.addresses.residential, profile.addresses.mailing (KYC), profile.addresses.registered, profile.addresses.physical (KYB, via OperatingAddress), and per-UBO profile.associated_persons[].address (KYB).
| Field | Type | Required at submit | Notes |
|---|---|---|---|
line1 | string | yes | At least 4 characters. |
line2 | string | no | |
city | string | yes | |
state | string | conditional | ISO-3166-2 subdivision (e.g. "NY"). Required when the country's address format includes a state / region (e.g. US, CA, HK); omit it for countries that don't use one (e.g. GB). |
postal_code | string | conditional | Required when the country's address format requires a postal code, and format-checked whenever supplied. |
country | string (ISO-3166 α-2) | yes | Two-letter code, e.g. "US". See Country codes. |
transliterated_address | TransliteratedAddress | conditional | Required when any canonical field above contains non-Latin-1 characters. |
No PO boxes.
Both conditional rules resolve per country. GET /customers/address-requirements answers them for one country ahead of submit, so a form can hide the fields that country's address format doesn't have.
OperatingAddress
profile.addresses.physical (KYB) only. Every Address field, sent inline.
| Field | Type | Required at submit | Notes |
|---|---|---|---|
remote | boolean | no | Deprecated. Set addresses.operating_is_remote instead. Still accepted as the same declaration, and still returned in step with operating_is_remote while an operating address is on file. |
operating_is_remote
Set profile.addresses.operating_is_remote (KYB) when the business has no office and the address it operates from is the residential address of a control person. Seismic adds a statement to that effect to the supplemental information document it sends to compliance review.
physical stays optional. Send it when the residence the business operates from is not the registered address already on the profile:
{
"addresses": {
"operating_is_remote": true,
"physical": {
"line1": "88 Cedar Ave",
"city": "Austin",
"state": "TX",
"postal_code": "78701",
"country": "US"
}
}
}The flag and the operating address have to agree, in both directions. Only beneficial owners count — an associated_persons entry without the beneficial_owner role has no residence the business can be operating out of:
- With the flag set and a
physicaladdress sent, that address must match the address of one of the profile's beneficial owners — otherwise submission fails with anotherviolation onaddresses.physical. - When
physicaldoes match a beneficial owner's address, the flag must be set — otherwise submission fails with anot_in_allowed_setviolation onaddresses.operating_is_remote.
Addresses are compared as premises, not as strings: casing, extra whitespace and postal-code separators don't matter, but Ave and Avenue are different addresses.
The declaration also covers the company's proof of address: the beneficial owner whose residential address matches the operating address proves it with their own proof_of_address document, so no company-level one is required at submit. A company proof_of_address uploaded anyway is deduplicated by file name against that person's document, or kept as other with the description "Alternate proof of address for the company".
Addresses sent without either flag read as operating_is_remote: false, so existing payloads are unaffected.
Country codes
Every country-valued field takes an ISO-3166-1 alpha-2 code: two uppercase letters, such as SG, US, GB. Country names are rejected — "Singapore" fails validation, "SG" is what the field wants. The same rule covers nationality, citizenship, country_of_birth, country_of_residence, phone_country_code, gov_id_country, country_of_registration, regulated_authority_country, and the jurisdiction arrays.
City-states repeat the name across the address. city keeps the human-readable name ("Singapore"), country still takes the code ("SG"), and state is omitted because Singapore's address format has no state or region. Not every city-state drops state: Hong Kong's format includes an area, so HK addresses require one.
Correct:
{
"line1": "1 Raffles Place",
"city": "Singapore",
"postal_code": "048616",
"country": "SG"
}Rejected:
{
"line1": "1 Raffles Place",
"city": "Singapore",
"state": "Singapore",
"postal_code": "048616",
"country": "Singapore"
}Phone numbers
Every profile phone (contact.phone, and phone on each associated person) is checked at submit in two steps:
- Shape. E.164:
+, the country calling code, then the national number, with no spaces or punctuation — 8–15 digits after the+. - Digits for the calling code. The number must fall in a real number range for its calling code, checked against published per-country numbering plans. Lengths vary by country and by line type, so there is no single digit count to aim for.
Two mistakes account for most rejections:
- The national trunk prefix is kept. A leading
0dialled inside the country is not part of the E.164 number: UK07911 123456is+447911123456, not+4407911123456. Italy is the exception — its leading0stays (+390212345678). - The calling code is typed twice. Singapore
8753 1018is+6587531018, not+656587531018.
A number that fails either step is rejected with invalid_format on its field, and the message names the calling code. A calling code with no published numbering plan is checked for shape only.
TransliteratedAddress
Latin-1 form of an address whose canonical fields contain non-Latin-1 characters (Cyrillic, CJK, Arabic, etc.). Sanctions / PEP screening runs against Latin-only databases, so the romanized form is required alongside the original. All-or-nothing: when the canonical address triggers the requirement, every required canonical field needs a Latin counterpart. country is omitted. ISO-3166 codes are always Latin-1.
| Field | Type | Required at submit | Notes |
|---|---|---|---|
line1 | string | yes | At least 4 characters. |
line2 | string | no | Supply it when canonical line2 is set. |
city | string | yes | |
state | string | no | Supply it when canonical state is set. |
postal_code | string | conditional | Same rule as the canonical postal_code. |
KycProfile
The unified individual-KYC profile body. Lives under profile on an individual customer envelope. Read it via GET /customers/:id/kyc/profile, write it via PUT /customers/:id/kyc/profile.
identity
| Field | Type | Required at submit | Notes |
|---|---|---|---|
first_name, last_name | string | yes | |
middle_name | string | no | |
transliterated_first_name | string | conditional | Latin-1 romanization. Required when the canonical name contains non-Latin-1 characters. |
transliterated_middle_name | string | conditional | Latin-1 romanization, when canonical middle_name contains non-Latin-1 characters. |
transliterated_last_name | string | conditional | Latin-1 romanization, when canonical last_name contains non-Latin-1 characters. |
date_of_birth | string (ISO-8601 date) | yes | YYYY-MM-DD. |
nationality | string (ISO-3166 α-2) | no | Passport country. Two-letter code, see Country codes. |
citizenship | string (ISO-3166 α-2) | no | May equal nationality. |
gender | "male" | "female" | no | Required before Seismic can provision a virtual account in some currencies. |
country_of_birth | string (ISO-3166 α-2) | no | Where the customer was born. Distinct from nationality and citizenship — a person can be born in a country whose passport and citizenship they do not hold. |
country_of_residence | string (ISO-3166 α-2) | yes | Often equal to nationality. Drives the tax-id rule below and sanctions screening. |
tax_identification_number | string | conditional | Tax id issued by the country of residence (SSN/ITIN for US residents). This individual field is identity.tax_identification_number; associated persons use tax_id. Required when country_of_residence === "US". |
social_profile_url | string (URL) | no | Link to the customer's profile on LinkedIn, Facebook, Instagram or X. Corroborates the identity on the government ID during review. Optional today; see Social profile. |
Social profile
identity.social_profile_url takes an http/https link to the customer's
profile on one of four networks:
linkedin.comfacebook.cominstagram.comx.com(twitter.comis accepted for links saved under the old domain)
Subdomains are fine, so https://www.linkedin.com/in/alice and
https://m.facebook.com/alice both pass. A link to any other host is
rejected at submit with a NotInAllowedSet violation on
identity.social_profile_url, and a value that isn't a usable link is
rejected as InvalidFormat.
The field is optional. Submissions that omit it succeed exactly as before. A future release will require it for customers whose government ID was issued outside the US, EU or Canada — that change will get its own changelog entry and advance notice before it takes effect.
addresses
| Field | Type | Required at submit | Notes |
|---|---|---|---|
residential | Address | yes | Where the customer lives. Must be a physical street address. A PO box is rejected at submit. |
mailing | Address | no | Optional separate mailing address. Defaults to residential when omitted. May be a PO box. |
contact
| Field | Type | Required at submit | Notes |
|---|---|---|---|
email | string | yes | Primary contact. |
phone | string | yes | E.164 required, valid for its calling code, e.g. +14155552671. See phone numbers. |
phone_country_code | string (ISO-3166 α-2) | yes | Country whose dialing code is on phone. |
employment
| Field | Type | Required at submit | Notes |
|---|---|---|---|
employment_status | EmploymentStatus | yes | |
employment_description | string | conditional | Required when employment_status === "other". Free-form. |
occupation_soc | string | yes | The individual's occupation, as a 6-digit SOC code (NN-NNNN) from the occupation codes catalog. A code outside the catalog is rejected. |
employer_name | string | no |
EmploymentStatus
One of:
employeeself_employedretiredunemployedhomemakerstudentother: setemployment_descriptionalongside.
risk
AML questionnaire. Self-attested.
| Field | Type | Required at submit | Notes |
|---|---|---|---|
primary_source_of_funds | SourceOfFunds | yes | Where the funds that will be flowing through the platform originate from. |
primary_source_of_funds_description | string | conditional | Required when primary_source_of_funds === "other". Free-form. |
source_of_wealth | string | no | How the individual has generally attained wealth — not necessarily the same as how transactions through the platform are funded. Send one of the SourceOfFunds values. Free text (max 256 characters) is accepted until November 1, 2026; from then it is required and must be one of those values. |
account_purpose | AccountPurpose | yes | Required for every individual customer. |
account_purpose_explanation | string | conditional | Required when account_purpose === "other". |
acting_as_intermediary | boolean | no | Whether this entity sits between any payer and payee. This includes marketplaces and fintech companies, even non-custodial ones that are not in the flow of funds. Defaults to false. |
pep_status | boolean | no | Politically Exposed Person, self-attested. Defaults to false. We record only the boolean, never the underlying role. |
SourceOfFunds
Where the customer's funds come from. One of:
salarysavingsbusiness_revenuecompany_capitalinvestment_returnsinheritancetrustgiftgrantsale_of_assetsreal_estateloanprivate_capitalmaritalwinningsother
On a business (KYB) profile, primary_source_of_funds_description is required whatever value is chosen. On an individual (KYC) profile, only other requires it.
AccountPurpose
Why the customer is opening this account. Every value is accepted for individual and business customers alike, but we recommend picking from the per-kind list below — a purpose outside its list can reach review as free text instead of a category, which clears slower. The hosted verification wizard offers exactly these, in this order; mirror it when you build your own form so a customer sees the same choices in the same order.
Recommended for a consumer (individual customer):
salary_collections: receive my salary.personal_use: pay for personal expenses.remittances: make payments to friends or family abroad.purchase_goods_and_services: pay for goods and services.savings: store savings.investment: make investments.freelance_collections: receive my freelance payments.charitable_donations: make charitable donations.other: setaccount_purpose_explanationalongside.
Recommended for a business customer:
purchase_goods_and_services: pay for goods and services.receive_payments_for_goods_and_services: receive payments for goods and services.investment: make investments.ecommerce_collections: accept retail e-commerce payments.charitable_donations: make or receive charitable donations.other: setaccount_purpose_explanationalongside.
Accepted, but not recommended for either kind:
crypto_investment: reviewed the same asinvestment. Sendinvestment.payroll: paying employees or contractors. Reviewed the same aspurchase_goods_and_services. Send that instead.business_operations: legacy. Accepted for existing integrations — submits asotherwith the purpose asaccount_purpose_explanation.treasury_management: legacy. Same handling asbusiness_operations.
volumes
Estimated transaction counts and exact USD figures. Nonnegative. 0 is valid.
| Field | Type | Required at submit | Notes |
|---|---|---|---|
usd_value_of_fiat | number | yes | Fiat activity per month, USD. |
usd_value_of_crypto | number | no | Crypto activity per month, USD. Defaults to 0 when omitted. |
monthly_deposits | integer | no | Fiat deposit count per month. |
monthly_withdrawals | integer | no | Fiat withdrawal count per month. |
monthly_crypto_deposits | integer | no | Crypto deposit count per month. Defaults to 0 when omitted. |
monthly_crypto_withdrawals | integer | no | Crypto withdrawal count per month. Defaults to 0 when omitted. |
monthly_investment_deposit_usd | number | no | Investment deposit value per month, USD. Defaults to 0 when omitted. |
monthly_investment_withdrawal_usd | number | no | Investment withdrawal value per month, USD. Defaults to 0 when omitted. |
monthly_crypto_investment_deposit_usd | number | no | Crypto investment deposit value per month, USD. Defaults to 0 when omitted. |
monthly_crypto_investment_withdrawal_usd | number | no | Crypto investment withdrawal value per month, USD. Defaults to 0 when omitted. |
expected_monthly_payments_usd | number | no | Exact expected monthly USD payments. Defaults to usd_value_of_fiat when omitted. |
jurisdictions
| Field | Type | Required at submit | Notes |
|---|---|---|---|
funds_send_receive_jurisdictions | array of ISO-3166 α-2 | no | Countries the user expects to send/receive funds to-from. |
high_risk_activities | array of HighRiskActivity | yes | Self-attested high-risk activities. Must be non-empty from 2026-09-14 — send ["none_of_the_above"] when none apply, so an unanswered question is never read as a negative answer. |
vendors_and_counterparties | array of CounterpartyType | no | Counterparty types the user transacts with. |
HighRiskActivity
One of:
adult_entertainmentgamblingmarijuanadrugsfirearmscrypto_mixing: operating a crypto tumbler / mixer service.money_serviceslending_or_bankingforeign_exchangehold_client_fundsinvestment_servicessafe_deposit_boxtobaccopharmaceuticalsthird_party_payment_processingnone_of_the_above: explicit negative. Exclusive — sending it alongside any other value is rejected at submit. Send it on its own to disclose that none apply.
BusinessClassification
One of:
marketplace: gig platforms, booking platforms, delivery apps, app stores.financial_services_provider: fintech companies, e.g. non-custodial neobanks, wallets, card programs, payment processors, remittance apps — including ones that never touch the flow of funds.none_of_the_above: explicit negative. Exclusive — sending it alongside any other value is rejected at submit. Send it on its own to disclose that none apply.
marketplace and financial_services_provider each imply acting_as_intermediary. Either one must also upload a flow_of_funds and a Provider Attestation (licensed_vendors_attestation) document at submit, and must answer in_flow_of_funds (true or false) — see documents.
CounterpartyType
Who the customer expects to transact with. One of:
self_transactionsmerchants_supplierscustomersemployeescontractorsfriendsfamily
attestations
Submission-time attestations. Both must be true at submit (some hosted KYC flows collect them on the form instead, when that's the case, leave them as the default false and they'll be set when the customer agrees in-flow).
| Field | Type | Required at submit | Notes |
|---|---|---|---|
terms_and_conditions_accepted | boolean | yes (true) | |
information_attested | boolean | yes (true) |
documents
Government-issued ID metadata + supporting documents. Bytes are uploaded separately via POST /customers/:id/kyc/documents. The profile carries document_id references.
| Field | Type | Required at submit | Notes |
|---|---|---|---|
government_issued_identification | GovernmentIdentification | yes | At least the front image is required. |
supporting_documents | array of SupportingDocumentRef | yes | Read-only. Derived from uploads through the documents endpoints; values sent in a profile PUT are ignored. Upload required evidence there, including selfie and proof of address when required at submit. |
GovernmentIdentification
| Field | Type | Required at submit | Notes |
|---|---|---|---|
kind | GovIdKind | yes | |
number | string | yes | Document number. |
country | string (ISO-3166 α-2) | yes | Issuing country. |
front_image_document_id | string (UUID) | yes | document_id for the front image, from POST /customers/:id/kyc/documents with the DocumentKind matching the ID type: passport for passports, identity_card_front for national IDs, or drivers_licence_front for driver's licenses. |
back_image_document_id | string (UUID) | conditional | Required for two-sided IDs (driver's license and national ID). Upload the back under the matching *_back kind (e.g. identity_card_back). Absent for passports, which are single-sided. |
issuance_date | string (ISO-8601 date) | no | When the document was issued (YYYY-MM-DD). |
expiration_date | string (ISO-8601 date) | no | When the document expires (YYYY-MM-DD). Optional in general, but required before an AED account can be opened. |
SupportingDocumentRef
| Field | Type | Required at submit | Notes |
|---|---|---|---|
kind | string | yes | One of the DocumentKind slugs (bank_statement, proof_of_address, etc.). |
document_id | string (UUID) | yes | document_id from a POST /customers/:id/kyc/documents upload. |
GovIdKind
New submissions accept:
passportdrivers_licensenational_id
Existing profile reads can also return legacy values:
residence_permitvoters_cardother
supplemental
Free-form entries for responding when review asks for more information — a text note or a supplemental document, each with a title and description. The section itself is optional at submit; the rules below apply to each entry sent. It is omitted from the response while empty, and profile saves are full-replace: a PUT /customers/:id/kyc/profile that omits supplemental clears the section, so echo the existing entries (with their ids) on every save they should survive.
| Field | Type | Required at submit | Notes |
|---|---|---|---|
id | string (UUID) | no (server-assigned) | Populated on read after the first save. Echo it back so the entry stays stable across saves. |
kind | "text" | "document" | yes | Whether the entry is a free-form note or references an uploaded document. |
title | string | conditional | Short label for the entry. Required when kind === "text". A document entry needs a title or a description saying what the file is; with neither, submit reports supplemental[i].title. |
description | string | conditional | The note body. Required when kind === "text"; for a document entry, required unless title is set. |
document_id | string (UUID) | conditional | Required when kind === "document". document_id from a POST /customers/:id/kyc/documents upload with kind=supplemental. |
Example
A fully-populated profile body for an individual customer:
{
"identity": {
"first_name": "Alice",
"middle_name": "Margaret",
"last_name": "Liddell",
"date_of_birth": "1985-06-15",
"nationality": "US",
"citizenship": "US",
"gender": "female",
"country_of_birth": "US",
"country_of_residence": "US",
"tax_identification_number": "123-45-6789",
"social_profile_url": "https://www.linkedin.com/in/alice-liddell"
},
"addresses": {
"residential": {
"line1": "1 Wall St",
"city": "New York",
"state": "NY",
"postal_code": "10005",
"country": "US"
}
},
"contact": {
"email": "alice@example.com",
"phone": "+12025550100",
"phone_country_code": "US"
},
"employment": {
"employment_status": "employee",
"occupation_soc": "15-1252",
"employer_name": "Acme Inc."
},
"risk": {
"primary_source_of_funds": "salary",
"source_of_wealth": "savings",
"account_purpose": "personal_use",
"acting_as_intermediary": false,
"pep_status": false
},
"volumes": {
"usd_value_of_fiat": 120000,
"usd_value_of_crypto": 25000,
"monthly_deposits": 4,
"monthly_withdrawals": 2,
"monthly_crypto_deposits": 1,
"monthly_crypto_withdrawals": 0,
"monthly_investment_deposit_usd": 500,
"monthly_investment_withdrawal_usd": 0,
"monthly_crypto_investment_deposit_usd": 0,
"monthly_crypto_investment_withdrawal_usd": 0
},
"jurisdictions": {
"funds_send_receive_jurisdictions": [
"US",
"GB"
],
"high_risk_activities": [
"none_of_the_above"
],
"vendors_and_counterparties": [
"self_transactions",
"merchants_suppliers"
]
},
"attestations": {
"terms_and_conditions_accepted": true,
"information_attested": true
},
"documents": {
"government_issued_identification": {
"kind": "passport",
"number": "X12345678",
"country": "US",
"front_image_document_id": "8e3b…"
},
"supporting_documents": [
{
"kind": "selfie",
"document_id": "c07a…"
},
{
"kind": "proof_of_address",
"document_id": "1f4d…"
}
]
},
"supplemental": [
{
"id": "0e8b…",
"kind": "text",
"title": "Clarification on settlement volumes",
"description": "Q3 volume increase reflects two new enterprise clients onboarded in July."
},
{
"id": "7f1a…",
"kind": "document",
"title": "March bank statement",
"description": "Statement covering the period referenced in the review.",
"document_id": "b2c3…"
}
]
}KybProfile
The unified business-KYB profile body. Lives under profile on a business customer envelope. Read it via GET /customers/:id/kyc/profile, write it via PUT /customers/:id/kyc/profile.
The shape matches the org's own KybProfile one-for-one. Same sub-sections, same enums, same submit-time validation. The difference is who's being verified: the integrator's own KYB lives under /v0/org/kyb/*. This body verifies the integrator's end-customer businesses.
business
| Field | Type | Required at submit | Notes |
|---|---|---|---|
legal_name | string | yes | Formal entity name as registered. |
trade_name | string | no | "Doing business as". Must differ from legal_name; omit it when the business has no DBA. When set, a dba_registration document is required at submit. |
transliterated_legal_name | string | conditional | Latin-1 romanization. Required when legal_name contains non-Latin-1 characters. |
transliterated_trade_name | string | no | Latin-1 romanization of trade_name. |
entity_type | EntityType | yes | |
corporate_entity_type_description | string | conditional | Required when entity_type === "other" or entity_type === "dao". Free-form. |
industry | string | yes | NAICS code, e.g. "425120". GET /industries lists the accepted set. Anything else is rejected as incomplete. |
description | string | yes | Description of the business: what product or service it provides, who its customers are, how it makes money, and how funds move through it. At least 350 characters at submit — reviewers need real detail to clear an entity. A shorter one fails with a too_short violation. From 2026-11-01, at most 1,000 characters (too_long). |
registration_number | string | yes | Government-issued company id (UK Companies House, etc.). |
tax_id | string | yes | EIN / equivalent. |
country_of_registration | string (ISO-3166 α-2) | yes | Two-letter code: "US", "GB", etc. See Country codes. |
state_of_incorporation | string | conditional | Required when country_of_registration === "US". |
formation_date | string (ISO-8601 date) | yes | When the entity was formed. |
website | string (URL) | conditional | Public-facing URL. Omit it when the entity has no public website — then marketing_strategy, website_eta, and social_media_profile are required. |
no_website | boolean | no | The entity has no public-facing website. Setting it clears website and makes marketing_strategy, website_eta, and social_media_profile required. Defaults to false. |
marketing_strategy | string | conditional | How the entity markets themselves to generate business. Required when the entity has no website; minimum 300 characters. Dropped on save when a website is given. |
website_eta | string (ISO-8601 date, or 0000-00-00) | conditional | When the entity expects to publish a website, or 0000-00-00 when it does not intend to. Required when the entity has no website; a dated value must be in the future (violations[] reason: "out_of_range"). Dropped on save when a website is given. |
social_media_profile | string (URL) | conditional | A social media profile of the entity (preferred) or of one of its beneficial owners, standing in for the website it does not have. Required when the entity has no website. Dropped on save when a website is given. |
target_customers_description | string | no | Who the business's target customers are: whether they are individuals or businesses, where they are located, and its top customer personas. Include the financial motivation for those customers to open accounts, and how they use them in practice — settlement methods, and inbound / outbound frequency and sizing. Seismic includes it in the supplemental information document it sends to compliance review. |
pre_revenue | boolean | no | The business has no revenue yet, so its proof of nature of business is alternative documentation of its preparations to operate rather than invoices or executed agreements. Seismic adds a statement to that effect to the supplemental information document it sends to compliance review. Defaults to false. Must be true exactly when volumes.estimated_annual_revenue_usd is 0. A pre-revenue business must also set operations.primary_source_of_funds to private_capital and upload a ubo_source_of_funds document. |
is_dao | boolean | no | Whether the entity is a DAO. Defaults to false. |
EntityType
One of:
sole_proprietorshipllcs_corporationc_corporationb_corporationnon_profitpartnershiplimited_partnershiplimited_liability_partnershiptrustdaocooperativeother
addresses
| Field | Type | Required at submit | Notes |
|---|---|---|---|
registered | Address | yes | Legal registered address. |
physical | OperatingAddress | no | Operating address if different. Defaults to registered when omitted. Note that the business' physical address cannot be a virtual address or an address of a registered agent. |
operating_is_remote | boolean | no | Defaults to false. Set it when the business operates remotely and the address it operates from is a control person's residence rather than an office — see operating_is_remote. |
contact
| Field | Type | Required at submit | Notes |
|---|---|---|---|
email | string | yes | Primary business contact. |
phone | string | yes | E.164 required, valid for its calling code, e.g. +14155552671. See phone numbers. |
phone_country_code | string (ISO-3166 α-2) | yes | Country whose dialing code is on phone. |
operations
Compliance / jurisdiction context.
| Field | Type | Required at submit | Notes |
|---|---|---|---|
business_jurisdictions | array of ISO-3166 α-2 | no | Where the business operates. |
funds_movement_jurisdictions | array of ISO-3166 α-2 | no | Where funds will be sent/received. Defaults to business_jurisdictions on read when omitted. |
primary_source_of_funds | SourceOfFunds | yes | The business's historical source of funds: where its funds have come from to date. |
primary_source_of_funds_description | string | yes | Free-form detail on the business's historical source of funds. Required at submit whatever primary_source_of_funds is set to. From 2026-11-01, 200 to 1,000 characters (too_short / too_long). |
source_of_wealth | SourceOfFunds | no | Where the business's overall wealth came from — the net-worth question, as opposed to primary_source_of_funds, the business's historical source of funds: where its funds have come from to date. Takes the same options as primary_source_of_funds. |
regulated_status | RegulatedStatus | yes | |
regulated_activity_description | string | conditional | Free-form description of the licensed activity. All four regulated_* fields are required together when regulated_status is regulated, registered, or licensed, or when any one of them is set. All four are null together when the business conducts no regulated activity. |
regulated_authority_country | string (ISO-3166 α-2) | conditional | Issuing authority's country. |
regulated_authority_name | string | conditional | Name of the regulatory authority. |
regulated_license_number | string | conditional | License number issued. |
account_purpose | AccountPurpose | yes | What the business plans to use the platform for. |
account_purpose_explanation | string | conditional | Required when account_purpose === "other" or primary_source_of_funds === "other". From 2026-11-01, 200 to 1,000 characters when given (too_short / too_long). From 2026-11-14, required whatever account_purpose is. |
registered_msb | boolean | no | Whether the business is registered as a money services business in any country. Defaults to false. Accepts the former conducts_money_services spelling on input. |
registered_msb_description | string | conditional | Required when registered_msb is true, and from 2026-11-01 also when in_flow_of_funds is true. Free-form. Accepts the former conducts_money_services_description spelling on input. |
licensed_vendors | boolean | no | Whether the business relies on licensed or regulated vendors as a core part of its operations. Defaults to false. When true, a Provider Attestation (licensed_vendors_attestation) document is required at submit (it is also required whenever business_classifications includes marketplace or financial_services_provider). |
msb_compliance_screening_description | string | conditional | Required when registered_msb is true, and from 2026-11-01 also when in_flow_of_funds is true. The compliance / AML screening program behind the registration. From 2026-11-01, at least 200 characters (too_short). |
high_risk_activities_description | string | conditional | Required when high_risk_activities names a real vertical. The business's involvement in the verticals it disclosed. |
compliance_screening_explanation | string | conditional | The combined screening narrative. Normally derived — the two fields above are concatenated under MSB COMPLIANCE SCREENING DESCRIPTION / HIGH RISK ACTIVITY DESCRIPTION headers, since compliance receives one field. Set it directly to supply the whole narrative yourself; required that way when operates_in_prohibited_countries is true, which has no granular field. From 2026-11-01, the narrative, headers included, may be at most 1,000 characters; a longer one fails with a too_long violation on each field feeding it. |
operates_in_prohibited_countries | boolean | no | Whether the business operates in jurisdictions on the platform's prohibited list. Defaults to false. |
high_risk_activities | array of HighRiskActivity | yes | Self-attestations. Must be non-empty from 2026-09-14 — send ["none_of_the_above"] when none apply, so an unanswered question is never read as a negative answer. |
has_complex_ownership | boolean | no | Set true when the business has UBOs requiring beneficial-owner disclosure. Defaults to false. |
business_classifications | array of BusinessClassification | yes | How the business positions itself between payers and payees. Must be non-empty from 2026-09-14 — send ["none_of_the_above"] when none apply. |
acting_as_intermediary | boolean | no | Whether this entity sits between any payer and payee. This includes marketplaces and fintech companies, even non-custodial ones that are not in the flow of funds. Defaults to false; implied by business_classifications. |
in_flow_of_funds | boolean | conditional | Whether the business will at any point receive, hold, control, convert, or transmit customer funds, fiat or digital. Asked of marketplaces and financial services providers; Seismic includes the answer in the supplemental information document it sends to compliance review. Required at submit for marketplaces and financial services providers; false is an answer. From 2026-11-01, true requires registered_msb_description and msb_compliance_screening_description. |
RegulatedStatus
One of:
regulatedregistered: set theregulated_*fields alongside.licensednot_required
volumes
Estimated monthly transaction counts plus exact USD figures. Nonnegative. 0 is valid.
| Field | Type | Required at submit | Notes |
|---|---|---|---|
monthly_deposits | integer | no | Fiat deposit count per month. |
monthly_withdrawals | integer | no | Fiat withdrawal count per month. |
monthly_crypto_deposits | integer | no | Crypto deposit count per month. Defaults to monthly_withdrawals when omitted and that count was given. |
monthly_crypto_withdrawals | integer | no | Crypto withdrawal count per month. Defaults to monthly_deposits when omitted and that count was given. |
monthly_investment_deposit_usd | number | no | Investment deposit value per month, USD. |
monthly_investment_withdrawal_usd | number | no | Investment withdrawal value per month, USD. |
monthly_crypto_investment_deposit_usd | number | no | Crypto investment deposit value per month, USD. |
monthly_crypto_investment_withdrawal_usd | number | no | Crypto investment withdrawal value per month, USD. |
usd_value_of_fiat | number | yes | Fiat activity per month, USD. |
usd_value_of_crypto | number | no | Crypto activity per month, USD. Defaults to usd_value_of_fiat when omitted. |
expected_monthly_payments_usd | number | no | Expected total monthly payment volume, USD. Defaults to usd_value_of_fiat when omitted. |
estimated_annual_revenue_usd | number | yes | Annual revenue, USD. Send 0 only for a business that has no revenue yet, and set business.pre_revenue to true alongside it. |
counterparties
| Field | Type | Required at submit |
|---|---|---|
counterparties | array of CounterpartyType | no |
attestations
Submission-time attestations. Both must be true at submit.
| Field | Type | Required at submit | Notes |
|---|---|---|---|
terms_and_conditions_accepted | boolean | yes (true) | |
information_attested | boolean | yes (true) |
associated_persons
Add all beneficial owners (individuals with ≥25% ownership) and directors. Every business must have at least one beneficial owner and at least one director, even if it is the same person.
At submit time:
- At least one entry is required.
- At least one entry must include
"beneficial_owner"in itsrolesarray. - Every entry whose
ownership_percentis 25 or more must include"beneficial_owner"in itsrolesarray. Below 25 the role is optional. - At least one entry must include
"control_person"or"officer"in itsrolesarray. - At least one entry must include
"authorized_signer"in itsrolesarray. - From November 14, 2026, every entry must also include at least one of
"control_person","officer","director", or"authorized_signer". An entry whose only role is"beneficial_owner"is rejected with a violation onassociated_persons[i].roles. - Every entry must carry a full government-ID block (
gov_id_kind,gov_id_number,gov_id_country, andgov_id_front_image_document_id), plus aselfie_document_idand aproof_of_address_document_id. - Sum of
ownership_percentacross all entries must be ≤ 100. Sums under 100 are accepted. The residual represents holders below the disclosure threshold (per FinCEN's CDD rule, only ≥25% holders need be individually identified). Values accept up to two decimal places, so fractional stakes (e.g. three owners at"33.33"each) sum to 100 instead of being forced to whole numbers that overshoot.
| Field | Type | Required at submit | Notes |
|---|---|---|---|
id | string (UUID) | no (server-assigned) | Populated on read after the first save. Required by POST /customers/:id/kyc/documents when uploading a per-person document. |
customer_id | string (UUID) | no | An individual customer in your organization that this person is. Links the two so Seismic verifies the human once instead of twice — see Linking a person to an individual customer. |
first_name, last_name | string | yes | |
middle_name | string | no | |
transliterated_first_name | string | conditional | Latin-1 romanization. Required when first_name contains non-Latin-1 characters. |
transliterated_middle_name | string | conditional | Latin-1 romanization. Required when middle_name is set and contains non-Latin-1 characters. |
transliterated_last_name | string | conditional | Latin-1 romanization. Required when last_name contains non-Latin-1 characters. |
date_of_birth | string (ISO-8601 date) | yes | |
email | string | yes | |
phone | string | yes | E.164 required, valid for its calling code, e.g. +14155552671. See phone numbers. |
phone_country_code | string (ISO-3166 α-2) | yes | Country whose dialing code is on phone. |
address | Address | yes | Mailing address. |
tax_id | string | yes | Tax id issued by the country of residence (SSN for US residents). |
nationality | string (ISO-3166 α-2) | no | Optional for every role. |
citizenship | string (ISO-3166 α-2) | no | Optional for every role; may equal nationality. |
gender | "male" | "female" | no | Required before Seismic can provision a virtual account in some currencies. |
country_of_birth | string (ISO-3166 α-2) | no | Where the person was born. Distinct from nationality and citizenship — a person can be born in a country whose passport and citizenship they do not hold. |
source_of_wealth | SourceOfWealth | no | Where this person's overall wealth came from. The net-worth question, as opposed to primary_source_of_funds, the business's historical source of funds: where its funds have come from to date. |
previous_economic_activity | array of EconomicActivity | no | What this person does for a living; more than one value can apply. |
ownership_percent | string (decimal, 0–100) | yes | Up to two decimal places (e.g. "33.33"). Sum across all entries must be ≤ 100. |
roles | array of AssociatedPersonRole | yes (non-empty) | At least one entry across all UBOs must include beneficial_owner, and so must every entry whose ownership_percent is 25 or more. From November 14, 2026, every entry must also include control_person, officer, director, or authorized_signer. |
title | string | yes | Job/role title (e.g. "CEO", "Director"). Required on every associated person, not only control persons and officers. |
relationship_established_at | string (ISO-8601 date) | yes | When the person's relationship with the business began (YYYY-MM-DD). |
gov_id_kind | GovIdKind | yes | Type of government-issued ID. |
gov_id_number | string | yes | The ID number as printed on the document. |
gov_id_country | string (ISO-3166 α-2) | yes | Issuing country. |
gov_id_front_image_document_id | string (UUID) | yes | document_id from a POST /customers/:id/kyc/documents upload with owner=person, person_id=<this id>, and the DocumentKind matching gov_id_kind: passport for passports, identity_card_front for national IDs, or drivers_licence_front for driver's licenses. |
gov_id_back_image_document_id | string (UUID) | conditional | Same shape as the front, uploaded under the matching *_back kind (e.g. drivers_licence_back). Required when gov_id_kind is drivers_license or national_id. Absent for passports. |
gov_id_issuance_date | string (ISO-8601 date) | no | When the ID was issued (YYYY-MM-DD). |
gov_id_expiration_date | string (ISO-8601 date) | no | When the ID expires (YYYY-MM-DD). Optional in general, but required before an AED account can be opened. |
selfie_document_id | string (UUID) | yes | document_id from a POST /customers/:id/kyc/documents upload with owner=person, person_id=<this id>, kind=selfie. |
proof_of_address_document_id | string (UUID) | yes | document_id from a POST /customers/:id/kyc/documents upload with owner=person, person_id=<this id>, kind=proof_of_address. |
Linking a person to an individual customer
The same human is often both an individual customer of yours and a beneficial owner on a business customer's KYB profile. Set customer_id on the associated person to the individual customer's id and Seismic treats them as one person, reusing that customer's verification instead of putting them through it a second time.
Seismic accepts the link only when the two records identify the same person beyond doubt. The individual customer must belong to your organization and must match the submitted person on at least one of:
tax_id(compared with formatting removed, so123-45-6789and123456789agree),email(case-insensitive), orfirst_nameandlast_name(case-insensitive) anddate_of_birth.
Anything short of that — an unknown id, a customer in another organization, or details that don't line up — rejects the whole profile save with a 422 kyb_profile_incomplete violation on associated_persons[i].customer_id.
Profile writes are full replacements, so a PUT that omits customer_id on a person removes any link that person had. Send the field on every save you want the link to survive.
The field applies to business customers only. Sending it on your organization's own KYB profile is rejected.
To find the customer to link rather than tracking the pairing yourself, ask GET /customers/:id/kyc/associated-persons/:person_id/link-suggestions — it returns the individual customers that already match this person under the rules above.
SourceOfWealth
One of:
salarydividendsproperty_rentalinvestmentinheritancegamblingdonation
EconomicActivity
Multi-select. An entry can carry any combination.
employedself_employedstudentgamblerpensionerunemployed
AssociatedPersonRole
Multi-select. An entry can carry any combination.
beneficial_owner: ≥25% direct or indirect ownership.control_person: exercises significant control / management.officer: named officer (CEO, CFO, etc.). Setstitle.director: board member.authorized_signer: empowered to sign on behalf of the entity.
supplemental
Free-form entries for responding when review asks for more information — a text note or a supplemental document, each with a title and description. The section itself is optional at submit; the rules below apply to each entry sent. It is omitted from the response while empty, and profile saves are full-replace: a PUT /customers/:id/kyc/profile that omits supplemental clears the section, so echo the existing entries (with their ids) on every save they should survive.
| Field | Type | Required at submit | Notes |
|---|---|---|---|
id | string (UUID) | no (server-assigned) | Populated on read after the first save. Echo it back so the entry stays stable across saves. |
kind | "text" | "document" | yes | Whether the entry is a free-form note or references an uploaded document. |
title | string | conditional | Short label for the entry. Required when kind === "text". A document entry needs a title or a description saying what the file is; with neither, submit reports supplemental[i].title. |
description | string | conditional | The note body. Required when kind === "text"; for a document entry, required unless title is set. |
document_id | string (UUID) | conditional | Required when kind === "document". document_id from a POST /customers/:id/kyc/documents upload with kind=supplemental. |
documents
Business-level supporting documents (incorporation certificate, bank statement, ownership chart, etc.). Bytes are uploaded separately via POST /customers/:id/kyc/documents. Read this list to see what's been uploaded against the customer (the per-UBO government IDs are tracked under each associated_persons[].gov_id_*_image_document_id).
Each entry is a KybDocumentRef.
Required: business_formation, ownership_information, proof_of_nature_of_business, plus either a bank_statement or a ubo_bank_statement together with a proof_of_address. A business that sets operations.registered_msb must upload a flow_of_funds. A business whose operations.business_classifications includes marketplace or financial_services_provider must upload a flow_of_funds and a Provider Attestation (licensed_vendors_attestation). A business that sets business.pre_revenue must upload a ubo_source_of_funds. An org's own KYB additionally requires a Provider Attestation and a flow_of_funds whatever its answers say. See Required at submit for the full rules and the missing[] paths each gap reports.
Example
A fully-populated profile body for a business customer:
{
"business": {
"legal_name": "Acme Inc.",
"trade_name": "Acme",
"description": "Acme Inc. operates a marketplace connecting suppliers and merchants worldwide.",
"entity_type": "c_corporation",
"is_dao": false,
"industry": "425120",
"registration_number": "1234567",
"tax_id": "82-1234567",
"country_of_registration": "US",
"state_of_incorporation": "DE",
"formation_date": "2020-04-12",
"website": "https://acme.example"
},
"addresses": {
"registered": {
"line1": "1 Wall St",
"city": "New York",
"state": "NY",
"postal_code": "10005",
"country": "US"
}
},
"contact": {
"email": "ops@acme.com",
"phone": "+12025550100",
"phone_country_code": "US"
},
"operations": {
"business_jurisdictions": [
"US"
],
"funds_movement_jurisdictions": [
"US",
"GB"
],
"primary_source_of_funds": "company_capital",
"regulated_status": "not_required",
"account_purpose": "purchase_goods_and_services",
"registered_msb": false,
"licensed_vendors": false,
"operates_in_prohibited_countries": false,
"high_risk_activities": [
"none_of_the_above"
],
"has_complex_ownership": false,
"business_classifications": [
"none_of_the_above"
],
"acting_as_intermediary": false
},
"volumes": {
"monthly_deposits": 35,
"monthly_withdrawals": 30,
"monthly_investment_deposit_usd": 0,
"monthly_investment_withdrawal_usd": 0,
"monthly_crypto_investment_deposit_usd": 0,
"monthly_crypto_investment_withdrawal_usd": 0,
"usd_value_of_fiat": 5000000,
"usd_value_of_crypto": 0,
"expected_monthly_payments_usd": 250000,
"estimated_annual_revenue_usd": 5000000
},
"counterparties": {
"counterparties": [
"customers",
"merchants_suppliers"
]
},
"attestations": {
"terms_and_conditions_accepted": true,
"information_attested": true
},
"associated_persons": [
{
"id": "5e3a…",
"first_name": "Alice",
"last_name": "Liddell",
"date_of_birth": "1985-06-15",
"email": "alice@acme.com",
"phone": "+12025550100",
"phone_country_code": "US",
"address": {
"line1": "1 Wall St",
"city": "New York",
"state": "NY",
"postal_code": "10005",
"country": "US"
},
"tax_id": "123-45-6789",
"nationality": "US",
"citizenship": "US",
"gender": "female",
"country_of_birth": "US",
"source_of_wealth": "salary",
"previous_economic_activity": [
"employed"
],
"ownership_percent": "100",
"roles": [
"beneficial_owner",
"officer",
"director",
"authorized_signer"
],
"title": "CEO",
"relationship_established_at": "2020-04-12",
"gov_id_kind": "passport",
"gov_id_number": "X12345678",
"gov_id_country": "US",
"gov_id_front_image_document_id": "8e3b…",
"selfie_document_id": "c07a…",
"proof_of_address_document_id": "b921…"
}
],
"supplemental": [
{
"id": "0e8b…",
"kind": "text",
"title": "Clarification on settlement volumes",
"description": "Q3 volume increase reflects two new enterprise clients onboarded in July."
},
{
"id": "7f1a…",
"kind": "document",
"title": "March bank statement",
"description": "Statement covering the period referenced in the review.",
"document_id": "b2c3…"
}
],
"documents": [
{
"document_id": "1f4d…",
"kind": "articles_of_association",
"filename": "acme-articles.pdf",
"content_type": "application/pdf",
"size_bytes": 184213,
"uploaded_at": "2026-05-10T20:14:21.045Z"
}
]
}KyStatus
The unified verification lifecycle, used for both kyc_status (on individuals) and kyb_status (on businesses).
| Value | Notes |
|---|---|
draft | Customer created and editable. Not yet submitted for verification. |
submitted | Profile received and under Seismic's review before verification begins. No hosted link yet. |
under_review | Verification in progress. |
approved | Verification passed. Account creation now callable. Editing the profile and resubmitting with the explicit ?resubmit_approved=1 opt-in re-verifies the updated details, and may move the status back into review until the re-check completes. |
rejected | The submission was rejected, by Seismic's review or during verification. rejection_reason carries the human-readable explanation. The customer can correct the profile and resubmit. |
terminally_rejected | A non-correctable decision. Unlike rejected, the profile is locked and the submit route refuses to re-drive the customer. |
paused | Seismic has placed a compliance hold on the customer. They cannot transact, and resubmitting the profile does not lift it. The hold is reversible — the status moves on once it is lifted. |
unknown | Verification backend returned a status we don't recognize. |
CustomerState
Polymorphic state envelope returned by POST /customers/:id/kyc/submit, POST /customers/:id/kyc/sync-approvals, GET /customers/:id/kyc/state, and POST /customers/:id/kyc/resync. The type discriminator picks the field names inside state (kyc_status / kyc_link for individuals, kyb_status / kyb_link for businesses). The rest of the field set is identical.
| Field | Type | Notes |
|---|---|---|
type | "individual" | "business" | Matches the customer's type. Picks the shape of state. |
state | object (see below) | Nested state body. |
state (KYC variant, when type === "individual"):
| Field | Type | Notes |
|---|---|---|
kyc_status | KyStatus | Rolled-up status. See KyStatus for values. |
kyc_link | object | null | A separate verification redirect of the form { url, expires_at }, distinct from the Seismic-hosted kyc_link on the Customer envelope. Present only when the verification flow requires an external redirect (e.g. a hosted document-capture step). null otherwise. expires_at is an RFC-3339 timestamp. |
missing_fields | array of string | Dotted paths into the profile that need to be filled. Empty after a clean submit. |
last_synced_at | string | RFC-3339 timestamp, millisecond precision, when the cached state was last reconciled. |
rejection_reason | string | null | Human-readable, when the rolled-up status is rejected. |
pending_rfi | boolean | An open request for information is outstanding, independent of kyc_status. See when requests are visible for which statuses it can be true at and what clears it. |
last_submitted_at | string (ISO-8601) | null | When the profile was last filed for verification. null until the first submission. Moves on every resubmission, which the status can't show on its own — a resubmit returns to the review it left. |
state (KYB variant, when type === "business"): same fields with kyb_status and kyb_link substituted for the kyc_* names.
Account
A working account. Embedded on the response to the four POST /customers/:id/accounts/{kind}/{origin} endpoints (under account, when one exists yet), returned by GET /accounts/:id, the per-kind GETs (fiat, crypto), and GET /accounts. Also embedded in quote responses when a leg resolves from an attached account.
Account normally represents a usable account. The creating lifecycle (still-pending, partial failures, retries) lives on the separate AccountCreationRequest resource, but so callers can watch one stream instead of two, a virtual account that Seismic hasn't finished provisioning (or couldn't provision) also appears here with status: "pending" / "failed".
kind + shape together determine the layout of details: kind=fiat, shape=us → details is a UsBankFiatAccount. kind=crypto, shape=evm → details is a CryptoAccount. Narrow on kind first, then narrow details structurally.
| Field | Type | Notes |
|---|---|---|
id | string | Our UUID. |
customer_id | string | Our customer UUID. |
kind | "fiat" | "crypto" | Top-level discriminator. Picks the layout of details. |
shape | FiatShape | CryptoShape | Refines within kind. Disjoint variant sets, "us"/"uk"/"iban"/… vs "evm", …. |
origin | "external" | "virtual" | external, caller-attached, account belongs to the customer at their own bank / wallet. virtual, provisioned by Seismic. |
currency | string | ISO-4217 or stablecoin symbol ("USD", "USDC", …). One currency per account today. |
rails | string[] | ["ach", "wire"], ["sepa", "swift"], ["base"], …. Plural, a US bank settles over multiple rails. Crypto returns a one-element array (one wallet = one chain). |
status | "pending" | "active" | "failed" | "closed" | active is the normal state. closed means the account has been retired: see Closed accounts. pending and failed only appear on virtual accounts: pending while Seismic is still provisioning, failed if provisioning couldn't complete and the account never became usable. For crypto, the entry is sourced from the underlying AccountCreationRequest and details.address is omitted. For fiat, the account exists from creation but details is absent until provisioning completes — there are no payable coordinates to show while pending. |
balance | string? | Funds credited to the account, in currency major units, as of balance_as_of. The stored figure is kept in sync as funds move. Present on virtual accounts: single-account reads refresh a never-synced balance at request time, while list reads may omit it until the first sync lands. Always absent on external accounts. See GET /accounts/:id/balance. |
available_balance | string? | Portion of balance spendable right now (total minus holds/pending). Absent when the distinction doesn't exist. |
balance_as_of | string? | ISO-8601. When Seismic last refreshed balance. |
created_at | string | ISO-8601. |
updated_at | string | ISO-8601. |
details | FiatAccount | CryptoAccount? | Per-shape detail block. Layout is determined by kind + shape. Absent on a virtual bank account until its identifiers are issued (pending / failed), and absent when status is "closed" — a retired account publishes no deposit instructions. See Closed accounts. Always present once active, and on external accounts. |
liquidation | object? | Present on virtual fiat accounts that auto-liquidate, whether the target was set at creation or added later. { account_id, address, currency } names the crypto account incoming fiat is auto-converted and settled to. developer_fee_bps (number, optional) echoes the fee in basis points (100 = 1%). can_turn_off (boolean) says whether DELETE /accounts/:id/liquidation will be accepted. See auto-liquidation. |
can_enable_liquidation | boolean? | Whether auto-liquidation can be turned on for this account via PUT /accounts/:id/liquidation. Present only on virtual bank accounts that don't already auto-liquidate; false or absent means a target can only be attached at creation. |
Closed accounts
A closed account has been retired. It can no longer receive deposits, and it carries no details — the field is absent, not blanked, so there is nothing to mistake for a live identifier. Any account number, IBAN or wallet address you previously showed for it must not be used again.
Closing is not deleting. A closed account keeps its place in GET /accounts and GET /accounts/:id, and its payments, deposits and orders stay queryable, so history stays intact. DELETE /accounts/:id is the destructive counterpart: a deleted account disappears from both endpoints.
Closure is announced on the account.updated webhook. The embedded account in that event reads status: "closed" and carries no details, so the event itself is enough to retire the account in your own systems — no follow-up read required.
To list them, filter on status=closed.
FiatShape
Discriminator for the fiat-side details block. Lists only the shapes wired end-to-end today, more land as Seismic adds settlement support.
"us" | "uk" | "iban" | "swift" | "cn_cnaps" | "hk_fps" | "sg_fast" | "in_ifsc" | "mx_clabe" | "ar_cbu" | "ph_bank" | "thb_bank" | "idr_bank" | "ca_eft" | "pk_iban" | "ng_bank" | "br_pix" | "br_bank" | "au_bsb" | "co_bank"
CryptoShape
Discriminator for the crypto-side details block. Lists only the shapes wired end-to-end today, more land as Seismic adds settlement support.
"evm" | "sol"
External crypto accounts accept evm and sol; the shape is inferred from the selected rail when omitted.
FiatAccount
Account.details (and AccountCreationRequest.details) when kind === "fiat". One of the concrete wired shapes, keyed by Account.shape. Narrow structurally on the present field set, "routing_number" in account.details selects the US-bank variant.
The request-side counterparts live on POST /customers/:id/accounts/fiat/external. Fiat external create accepts the bank-identifier fields under details and the legal owner under top-level account_holder. Response details includes account_holder_name derived from that holder block where applicable.
On a virtual account, account_holder_name starts as the account holder's name and is replaced by the beneficiary name the issuing bank prints once the account is active. Quote the active account's account_holder_name in payment instructions.
shape: "us"
| Field | Type | Notes |
|---|---|---|
account_number | string | Bank account number. |
routing_number | string | The account's ABA routing number: the one quoted for an ACH credit when the account has one, otherwise the one quoted for a Fedwire credit. Always present, whatever the account settles over; the per-rail fields below say which credits each number may actually be quoted for. |
ach_routing_number | string? | ABA routing number to quote for an ACH credit. Absent when the account does not settle over ACH. |
fedwire_routing_number | string? | ABA routing number to quote for a Fedwire credit. A bank that publishes a separate wire ABA reports it here; otherwise an account that settles over wire routes it off the same nine digits as ach_routing_number and reports those. Absent on an account that does not settle over wire. |
rtp_routing_number | string? | ABA routing number to quote for an instant (RTP) credit, when the issuing bank publishes one distinct from ach_routing_number. Absent otherwise. |
bic | string? | BIC to quote for an inbound international wire, alongside swift_account_number. Absent when the account is reachable domestically only. |
swift_account_number | string? | The account number a foreign sender quotes for an international wire. Distinct from account_number, which is the domestic one: the payment is often received through a correspondent, so this can be an IBAN at another bank. Absent when the account is reachable domestically only. |
bank_name | string? | Display name of the bank, when known. |
account_holder_name | string | Name on the account. |
bank_address | Address | Mailing address registered with the bank. |
shape: "uk"
| Field | Type | Notes |
|---|---|---|
sort_code | string | 6-digit UK sort code. |
account_number | string | UK domestic account number. |
iban | string? | Optional cross-border IBAN form. |
bank_name | string? | Display name of the bank, when known. |
account_holder_name | string | Name on the account. |
bank_address | Address | Mailing address registered with the bank. |
shape: "swift"
| Field | Type | Notes |
|---|---|---|
bic | string | BIC / SWIFT code. |
account_number | string | IBAN or domestic account number. |
phone | string? | Holder contact phone, when supplied. |
tax_number | string? | Holder tax identification number, when supplied. |
bank_name | string | Bank display/routing name. |
account_holder_name | string | Name on the account. |
bank_address | Address | Mailing address registered with the bank. |
shape: "iban"
| Field | Type | Notes |
|---|---|---|
account_number | string | The IBAN string. |
bic | string? | BIC to quote for an inbound international wire, alongside swift_account_number. Absent when the account is reachable domestically only. |
swift_account_number | string? | The account number a foreign sender quotes for an international wire. Distinct from account_number, which is the domestic one: the payment is often received through a correspondent, so this can be an IBAN at another bank. Absent when the account is reachable domestically only. |
bank_code | string? | Domestic bank code (e.g. Swedish clearing number), when supplied. |
phone | string? | Holder contact phone, when supplied. |
id_number | string? | Holder government ID number, when supplied. Individuals only. |
id_type | string? | Kind of ID id_number carries, when supplied. Individuals only. |
registration_number | string? | Business registration number, when supplied. Businesses only. |
registration_type | string? | Kind of registration registration_number carries, when supplied. Businesses only. |
bank_name | string? | Display name of the bank, when known. |
account_holder_name | string | Name on the account. |
bank_address | Address | Mailing address registered with the bank. |
shape: "cn_cnaps"
| Field | Type | Notes |
|---|---|---|
account_number | string | Chinese domestic bank account number. |
cnaps_code | string | CNAPS bank / branch routing code. |
id_number | string | Holder tax / government ID number. |
id_type | string? | Kind of ID id_number carries, when supplied. Individuals only. |
registration_number | string? | Business registration number, when supplied. Businesses only. |
registration_type | string? | Kind of registration registration_number carries, when supplied. Businesses only. |
bank_name | string? | Display name of the bank, when known. |
branch_name | string? | Destination bank branch name (Hanzi), when supplied. Businesses only. |
account_holder_name | string | Name on the account. |
bank_address | Address | Mailing address registered with the bank. |
shape: "hk_fps"
| Field | Type | Notes |
|---|---|---|
account_number | string | Hong Kong destination account number. |
bic | string? | ISO 9362 BIC / SWIFT code of the destination bank — settlement routes on it. Absent only on accounts registered before it was collected. |
bank_name | string? | Display name of the bank, when supplied. |
registration_number | string? | Business registration number, when supplied. Businesses only. |
registration_type | string? | Kind of registration registration_number carries, when supplied. Businesses only. |
date_of_incorporation | string? | Incorporation date (YYYY-MM-DD), when supplied. Businesses only. |
account_holder_name | string | Name on the account. |
bank_address | Address | Mailing address registered with the bank. |
shape: "sg_fast"
| Field | Type | Notes |
|---|---|---|
account_number | string | Singapore destination account number. |
bank_name | string | Bank display/routing name. |
phone | string | Holder contact phone for the corridor. |
id_number | string? | Holder government ID number, when supplied. Individuals only. |
id_type | string? | Kind of ID id_number carries, when supplied. Individuals only. |
registration_number | string? | Business registration number (e.g. UEN), when supplied. Businesses only. |
registration_type | string? | Kind of registration registration_number carries, when supplied. Businesses only. |
relationship_to_debtor | string? | Holder's relationship to the customer as a fixed 4-letter code, when supplied. |
account_holder_name | string | Name on the account. |
bank_address | Address | Mailing address registered with the bank. |
shape: "in_ifsc"
| Field | Type | Notes |
|---|---|---|
ifsc | string | IFSC code (e.g. HDFC0001234). |
account_number | string | Indian domestic account number. |
phone | string? | Holder contact phone, when supplied. |
id_number | string? | Holder government ID number, when supplied. Individuals only. |
id_type | string? | Kind of ID id_number carries, when supplied. Individuals only. |
registration_number | string? | Business registration number, when supplied. Businesses only. |
registration_type | string? | Kind of registration registration_number carries, when supplied. Businesses only. |
relationship_to_debtor | string? | Holder's relationship to the customer as a fixed 4-letter code, when supplied. |
bank_name | string? | Display name of the bank, when known. |
account_holder_name | string | Name on the account. |
bank_address | Address | Mailing address registered with the bank. |
shape: "mx_clabe"
| Field | Type | Notes |
|---|---|---|
clabe | string | 18-digit CLABE. |
tax_number | string? | Holder tax id (RFC), when supplied. |
bank_name | string? | Display name of the bank, when known. |
account_holder_name | string | Name on the account. |
bank_address | Address | Mailing address registered with the bank. |
shape: "ar_cbu"
| Field | Type | Notes |
|---|---|---|
cbu | string | 22-digit CBU. |
alias | string? | CBU alias, when set. |
tax_number | string | Holder CUIT. |
phone | string | Holder contact phone. |
id_number | string? | Holder government ID number, when supplied. Individuals only. |
id_type | string? | Kind of ID id_number carries, when supplied. Individuals only. |
registration_number | string? | Business registration number, when supplied. Businesses only. |
registration_type | string? | Kind of registration registration_number carries, when supplied. Businesses only. |
bank_name | string | Display name of the bank. |
account_holder_name | string | Name on the account. |
bank_address | Address | Mailing address registered with the bank. |
shape: "ph_bank"
| Field | Type | Notes |
|---|---|---|
account_number | string | Philippine domestic account number. |
bank_name | string | Display name of the bank. |
phone | string? | Holder contact phone, when supplied. |
registration_number | string? | Business registration number, when supplied. Businesses only. |
registration_type | string? | Kind of registration registration_number carries, when supplied. Businesses only. |
date_of_incorporation | string? | Incorporation date (YYYY-MM-DD), when supplied. Businesses only. |
relationship_to_debtor | string? | Holder's relationship to the customer as a fixed 4-letter code, when supplied. |
account_holder_name | string | Name on the account. |
bank_address | Address | Mailing address registered with the bank. |
shape: "thb_bank"
| Field | Type | Notes |
|---|---|---|
account_number | string | Thai domestic account number. |
bank_name | string | Display name of the bank. |
account_holder_name | string | Name on the account. |
bank_address | Address | Mailing address registered with the bank. |
shape: "idr_bank"
| Field | Type | Notes |
|---|---|---|
account_number | string | Indonesian domestic account number. |
bank_name | string | Display name of the bank. |
account_holder_name | string | Name on the account. |
bank_address | Address | Mailing address registered with the bank. |
shape: "ca_eft"
| Field | Type | Notes |
|---|---|---|
institution_number | string | 3-digit bank identifier. |
transit_number | string | 5-digit branch identifier. |
account_number | string | Canadian domestic account number. |
bank_name | string | Name of the destination bank. |
account_holder_name | string | Name on the account. |
bank_address | Address | Mailing address registered with the bank. |
shape: "pk_iban"
| Field | Type | Notes |
|---|---|---|
iban | string | Pakistan IBAN (24 chars). |
bank_name | string? | Display name of the bank, when known. |
account_holder_name | string | Name on the account. |
bank_address | Address | Mailing address registered with the bank. |
shape: "ng_bank"
| Field | Type | Notes |
|---|---|---|
account_number | string | NUBAN account number (10 digits). |
bank_code | string | Numeric bank code, the routing key. |
bank_name | string? | Display name of the bank, when known. |
account_holder_name | string | Name on the account. |
bank_address | Address | Mailing address registered with the bank. |
shape: "br_pix"
| Field | Type | Notes |
|---|---|---|
pix_key | string | The PIX key. |
pix_key_type | string | cpf, cnpj, email, phone, or evp. |
account_holder_name | string | Name on the account. |
bank_address | Address | Mailing address registered with the bank. |
shape: "br_bank"
| Field | Type | Notes |
|---|---|---|
bank_code | string | COMPE or ISPB bank code. |
agency | string | Branch code, optionally with a check digit. |
account_number | string | Brazilian domestic account number. |
account_subtype | string | cc (checking) or pp (savings). |
tax_number | string? | Holder CPF or CNPJ, when known. |
phone | string? | Holder contact phone, when supplied. |
id_number | string? | Holder government ID number, when supplied. Individuals only. |
id_type | string? | Kind of ID id_number carries, when supplied. Individuals only. |
registration_number | string? | Business registration number (e.g. CNPJ), when supplied. Businesses only. |
registration_type | string? | Kind of registration registration_number carries, when supplied. Businesses only. |
bank_name | string? | Display name of the bank, when known. |
account_holder_name | string | Name on the account. |
bank_address | Address | Mailing address registered with the bank. |
shape: "au_bsb"
| Field | Type | Notes |
|---|---|---|
bsb | string | 6-digit Bank-State-Branch code. |
account_number | string | Australian domestic account number. |
account_holder_name | string | Name on the account. |
bank_address | Address | Mailing address registered with the bank. |
shape: "co_bank"
| Field | Type | Notes |
|---|---|---|
bank_code | string | Bank code as published by the Colombian banking association. |
account_number | string | Colombian domestic account number. |
account_type | string | CHECKING or SAVINGS. |
id_type | string | Kind of identity document id_number carries: CC, CE, NIT, PASS or PEP. |
id_number | string | The holder's identity document number. |
account_holder_name | string | Name on the account. |
bank_address | Address | Mailing address registered with the bank. |
CryptoAccount
Account.details (and AccountCreationRequest.details) when kind === "crypto". Same shape on the request side (POST /customers/:id/accounts/crypto/external) for origin: "external".
| Field | Type | Notes |
|---|---|---|
address | string (optional) | On-chain wallet address (EVM checksum, …). Omitted on a virtual crypto account while Account.status === "pending": Seismic is still provisioning the wallet. The field appears once provisioning completes. Also omitted when Account.status === "failed", where no address is coming. |
AccountCreationRequest
Returned by the four POST /customers/:id/accounts/{kind}/{origin} endpoints (under request), GET /customers/:id/accounts/requests/:id, and the idempotency-key lookup. Carries the lifecycle of the creation, distinct from the Account it produces, which only exists once Seismic has finished registering / provisioning.
details mirrors the materialized Account.details. For origin: "external", details is always set from the caller-supplied bank / wallet info. Fiat responses add account_holder_name from the top-level account_holder block where applicable. For origin: "virtual", details is absent until provisioning completes. Callers can still derive the eventual layout from kind + shape.
| Field | Type | Notes |
|---|---|---|
id | string | Our UUID for the creation request. |
customer_id | string | The customer this request creates an account for. |
kind | "fiat" | "crypto" | |
shape | FiatShape | CryptoShape | |
origin | "external" | "virtual" | |
currency | string | As supplied on (or inferred for) the request body. |
rails | string[] | Inferred for fiat (per-currency defaults today). Single-element for crypto (the one rail the wallet lives on). |
status | "pending" | "completed" | "failed" | pending while Seismic is still registering / provisioning. completed once the registration succeeds and the Account row exists. failed only if Seismic couldn't register the account. |
idempotency_key | string | The key the request was created with (caller-supplied or server-minted). |
account_id | string? | The id of the materialized Account once one exists. Populated synchronously for origin: "external". For virtual it lands once provisioning completes. |
details | FiatAccount | CryptoAccount? | Caller-echoed (external) or populated by Seismic once provisioning completes (virtual). Absent until populated. |
created_at | string | ISO-8601. |
updated_at | string | ISO-8601. |