Skip to content
Seismic Orchestration

Documents

Supporting documents (incorporation certificate, bank statement, government IDs, etc.) attach to the org's KYB profile or to a specific associated person. The bytes live in object storage. The API surface is a metadata table the dashboard renders and the submit step consumes when running the org's verification checks.

Documents accumulate across saves of the profile. They do not reset when PUT /org/kyb/profile re-saves a draft. Re-uploading the same (owner, kind) slot creates a new version with a new document_id and soft-deletes the prior one. Only the latest live version appears in GET /org/kyb/documents and feeds into submit. The prior row is retained in the database (deleted_at set) for compliance audit, but it isn't exposed back through the API.

All endpoints accept either Authorization: Bearer <jwt> or Api-Key: <key>. All endpoints, including reads and downloads, require role admin or owner.

Endpoints

POST /org/kyb/documents

Upload a supporting document. The body is multipart/form-data with the following fields.

FieldRequiredNotes
kindyesOne of the DocumentKind variants below.
owneryesorg or person. Picks which entity the document attaches to.
person_idconditionalUUID of the associated person. Required when owner=person. Ignored otherwise.
descriptionconditionalFree-text label, up to 256 characters. Required when kind=other unless purpose=rfi_answer: the free-form catch-all needs it so reviewers can tell attachments apart. Optional (and typically omitted) for every other kind. A blank or whitespace-only value counts as absent.
purposenorfi_answer when the file answers an open request for information. The request names the file, so an other upload sent with it needs no description. Omit for a plain profile upload.
fileyesThe file bytes. Up to 5 MB, and PDFs at most 200 pages. application/pdf, image/jpeg, or image/png. Both the content type and the filename extension are checked. Anything else (spreadsheets, Word documents, …) is rejected with 400 UnsupportedDocumentType. A PDF longer than 20 pages is split at upload — the first 20 pages are stored under the kind you sent and returned here, and each further span of 20 pages is stored as an extra other document named FILENAME_2.pdf, FILENAME_3.pdf, … A PDF under 10 KB gets a filler page appended so it clears the 10 KB verification floor. See Preparing documents before upload.

Idempotent against the latest live row in the slot: re-uploading byte-identical content for an existing (owner, kind) returns that document unchanged. Re-uploading different content supersedes the prior live version: the new document gets a new document_id and the prior row is soft-deleted in the same call. After a separate DELETE on a slot, re-uploading the same bytes creates a fresh document with a new document_id. The soft-deleted row stays soft-deleted.

other is the exception. The other kind isn't a single slot. It's a free-form catch-all that accepts any number of documents. Uploads under other never supersede or dedupe: each one creates a new document_id, so you can attach as many as you like. Because they'd otherwise be indistinguishable, every other upload must include a non-empty description (a missing one is rejected with 400). The one exception is an upload sent with purpose=rfi_answer: the request for information it answers already names the file.

Response 200: the saved KybDocumentRef:

{
  "document_id": "8c9d…",
  "kind": "articles_of_association",
  "filename": "acme-articles.pdf",
  "content_type": "application/pdf",
  "size_bytes": 184213,
  "uploaded_at": "2026-05-10T20:14:21.045Z"
}

Errors:

  • 400: bad multipart body, unknown kind, unknown purpose, missing required field, person_id absent when owner=person, description absent when kind=other (without purpose=rfi_answer), a description longer than 256 characters, empty file, an unsupported file type (UnsupportedDocumentType: documents must be PDF, JPEG, or PNG), or a PDF longer than 200 pages.
  • 403: caller is not an admin/owner of the org.
  • 404: person_id does not belong to this org's KYB profile.
  • 413: file exceeds 5 MB (KybDocumentTooLarge), or the multipart request exceeds 12 MB.
  • 503: document storage is not configured on this server (no GCS_BUCKET).

Example: uploading the articles of incorporation:

curl -X POST "$SEISMIC_ORCHESTRATION_URL/v0/org/kyb/documents" \
  -H "Api-Key: $SEISMIC_ORCHESTRATION_API_KEY" \
  -F "kind=articles_of_association" \
  -F "owner=org" \
  -F "file=@./acme-articles.pdf"

Example: attaching a UBO's government ID front-image to a specific person:

curl -X POST "$SEISMIC_ORCHESTRATION_URL/v0/org/kyb/documents" \
  -H "Api-Key: $SEISMIC_ORCHESTRATION_API_KEY" \
  -F "kind=government_issued_id" \
  -F "owner=person" \
  -F "person_id=2455…" \
  -F "file=@./jane-license-front.jpg"

After upload, store the returned document_id on the corresponding associated_persons[].gov_id_front_image_document_id (or gov_id_back_image_document_id) so it travels with the profile when you submit.

Example: attaching an other document, which requires a description:

curl -X POST "$SEISMIC_ORCHESTRATION_URL/v0/org/kyb/documents" \
  -H "Api-Key: $SEISMIC_ORCHESTRATION_API_KEY" \
  -F "kind=other" \
  -F "owner=org" \
  -F "description=Prior verification approval" \
  -F "file=@./approval-letter.pdf"

GET /org/kyb/documents

List every non-deleted document attached to the org's KYB profile or to any of its associated persons.

Response 200: array of KybDocumentRef ordered by uploaded_at ascending:

[
  {
    "document_id": "8c9d…",
    "kind": "articles_of_association",
    "filename": "acme-articles.pdf",
    "content_type": "application/pdf",
    "size_bytes": 184213,
    "uploaded_at": "2026-05-10T20:14:21.045Z"
  },
  {
    "document_id": "a1f2…",
    "kind": "government_issued_id",
    "filename": "jane-license-front.jpg",
    "content_type": "image/jpeg",
    "size_bytes": 154777,
    "uploaded_at": "2026-05-10T20:39:26.495Z"
  }
]

Errors:

  • 404: no KYB profile exists for the caller's org. Save a draft via PUT /org/kyb/profile first. An empty body is fine.

size_bytes is the exact byte count of the stored object. content_type is what the uploader sent. The server doesn't re-sniff the file.

Example:

curl -X GET "$SEISMIC_ORCHESTRATION_URL/v0/org/kyb/documents" \
  -H "Api-Key: $SEISMIC_ORCHESTRATION_API_KEY"

GET /org/kyb/documents/:id

Download a document's bytes, for example to let a user re-check which file they attached to a slot. Only organization owners and administrators can call it.

Response 200: the raw file bytes. Content-Type is the stored MIME type and Content-Disposition carries the original upload filename:

Content-Type: application/pdf
Content-Disposition: attachment; filename="acme-articles.pdf"

Errors:

  • 404: no document with that id belongs to this org. Same response for "never existed", "belongs to a different org", and "soft-deleted" so existence isn't leaked.
  • 503: document storage is not configured on this server.

Example: -OJ saves the file under its original name:

curl -OJ "$SEISMIC_ORCHESTRATION_URL/v0/org/kyb/documents/8c9d…" \
  -H "Api-Key: $SEISMIC_ORCHESTRATION_API_KEY"

DELETE /org/kyb/documents/:id

Soft-delete a document. The DB row is marked deleted_at and disappears from GET /org/kyb/documents. The underlying object in storage is retained for audit / compliance.

Response 204: empty body on success.

Errors:

  • 403: caller is not an admin/owner of the org.
  • 404: no document with that id belongs to this org. Same response for "never existed" and "exists but belongs to a different org" so cross-org existence isn't leaked.
  • 503: document storage is not configured on this server.

Example:

curl -X DELETE "$SEISMIC_ORCHESTRATION_URL/v0/org/kyb/documents/8c9d…" \
  -H "Api-Key: $SEISMIC_ORCHESTRATION_API_KEY"

To replace a slot, upload a new file with the same (owner, kind). The prior version is soft-deleted in the same call and the new file becomes the live row for that slot. You don't need to call DELETE first.

DocumentKind

One of:

  • business_formation: the filed formation document — for example Articles of Incorporation, Articles of Organization, or a Certificate of Incorporation. Must be the original document from the time of formation; a later document such as a Certificate Confirming Registration is not accepted.
  • articles_of_association: optional. A constitutional document that outlines how the entity is governed, which includes details such as how many directors it should have and who can exert control. The title for this differs per region, but it is typically referred to as Articles of Association, Bylaws, or Memorandum of Association.
  • dba_registration: a government-issued DBA certificate or registration for the trade name in business.trade_name. Required at submit whenever business.trade_name is set; not relevant otherwise.
  • memorandum_of_association: optional. Accepted as a distinct kind for jurisdictions that file a memorandum separately from the articles. Prefer articles_of_association when one document covers both.
  • bank_statement: the business's own statements from the last three full months. The last statement in the sequence should cover a period within 30 days of today. It should reasonably demonstrate the business' current operating activity and financial capacity; if it does not, also upload a ubo_bank_statement. The statement should also include both the entity name and the submitted operating address. If it does not, also upload a proof_of_address.
  • ubo_bank_statement: an ultimate beneficial owner's personal statements for the last three full months, evidencing the business' source of funds when it does not keep a business account of its own. The last statement in the sequence should cover a period within 30 days of today. They should reasonably demonstrate the business' current financial capacity as funded by that owner. Together with a proof_of_address, satisfies the financing-and-operations requirement when no bank_statement is uploaded.
  • shareholder_register: the entity's official shareholder / member register showing current holders and their stakes.
  • ownership_information: a table listing all shareholders and their ownership percentages. Shareholders holding 25% or more must be listed by full legal name. Shareholders holding less than 25% may be grouped into named buckets (e.g. "Team Members", "Seed Investors", "Unallocated Reserves"). Percentages must sum to 100%. Must include a date and signature from an authorized signatory, such as a control person, lawyer, or CPA. If the entity is partially owned by other entities holding 25% or more, please a) include ownership information for each one, recursing until you reach the natural beneficial owners, and b) add business formation documents for each of the other entities under the Supplemental section.
  • certificate_of_incumbency: a document confirming the entity's current officers, directors, managers, or authorized signatories. Unlike ownership_information, it names who is currently authorized to act for the entity, not only who owns it. Include full legal names, titles, and a current date, issued or certified by an authorized party. Must be dated and signed by a control person.
  • flow_of_funds: diagram showing your complete transaction flow. Must include payers and payees, existing financial service providers, and a highlighted zone where our platform comes into play. Must clearly document what party owns or controls each account or wallet through which funds move. Always required.
  • proof_of_nature_of_business: evidence showing the business generating income from the type of business activities claimed by the entity (e.g. invoices, executed agreements). The document should reflect the business as the service provider, not the client. If the business is pre-revenue and does not yet have invoices or customer agreements, provide any alternative documentation demonstrating the business' preparations to operate (e.g. a vendor or supplier agreement, a business plan) and set business.pre_revenue on the profile.
  • compliance_screening: the business's written AML/CTF program — the controls it operates, who is accountable for them, and how they are monitored. Output of screening the business runs internally is accepted where it has no written policy.
  • government_issued_id: legacy catch-all for any government ID. Still accepted, but because a slot holds one live document it can only carry one image — prefer the per-side kinds below.
  • Per-side government ID kinds, for both org-level and per-UBO uploads. Every gov-ID upload must be a photo of the original document with at least an inch of space around all four sides; scans and photocopies are not accepted.
    • passport: photo page of a passport. Passports are single-sided; there is no passport_back.
    • drivers_licence_front / drivers_licence_back
    • identity_card_front / identity_card_back
  • selfie: per-UBO only: a photo of the person's face, taken the same day on their own device.
  • proof_of_address: Must be a bank statement, utility bill, rent payment, or government letter issued within 60 days. If this is not available, we can also accept a lease agreement. Must clearly state the entity's name and submitted operating address. For a per-UBO upload: Must be a bank statement, utility bill, rent payment, or government letter issued within 60 days. If this is not available, we can also accept a residential lease agreement. Must clearly state the individual's full name and submitted address.
  • proof_of_source_of_funds: retired on 2026-10-07 in favour of ubo_bank_statement. New uploads are rejected with 400 and a document already on file no longer counts towards the financing-and-operations requirement; it is still returned by reads.
  • ubo_source_of_funds: documents showing where a beneficial owner's own funds came from, such as paystubs, W-2s, brokerage statements, asset sale agreements, or dividend vouchers. For a pre-revenue business, which is funded by its owners rather than by revenue — see Pre-revenue businesses. If a ubo_bank_statement is also uploaded, both must belong to the same beneficial owner.
  • tax_document: tax certificate, tax-residency letter.
  • licensed_vendors_attestation: the Provider Attestation, a list of the licensed or regulated service providers that play core roles in the business — no need to enumerate every one in the stack. Sign and date it with a control person. Always required.
  • proof_of_licensure: official license certificate or authorization letter issued by the regulator, demonstrating the business is registered to provide its stated activities. Required when operations.regulated_status is licensed.
  • supplemental: a document backing an entry in the profile's supplemental section. Accepts multiple documents — an owner may hold many — and no description is required at upload; the profile entry carries the title and description, and needs at least one of them at submit.
  • other: anything else the platform asks for during review. Unlike the slot kinds, other accepts multiple documents, and each upload must include a non-empty description (see POST /org/kyb/documents).

Required at submit, surfaced as missing[] paths under documents by POST /org/kyb/submit:

  • business_formation: the original filed formation document — see DocumentKind for what counts. When missing the validator reports the path documents.business_formation.

  • ownership_information

  • proof_of_nature_of_business. Still required for a pre-revenue business — see Pre-revenue businesses for what to upload instead of invoices.

  • licensed_vendors_attestation (the Provider Attestation). When missing the validator reports the path documents.licensed_vendors_attestation.

  • flow_of_funds. When missing the validator reports the path documents.flow_of_funds.

  • financing and operations: a bank_statement satisfies this on its own (it doubles as proof of source of funds and proof of address — Seismic forwards it as both), or a ubo_bank_statement together with a proof_of_address. Uploading all three is not required, but doing so speeds up verification by 30%. When no route is satisfied the validator reports the aggregate path documents.bank_statement_or_proof_of_source_of_funds_with_proof_of_address — the path keeps its historical name so existing integrations that match on it are unaffected.

    When the profile sets addresses.operating_is_remote, the beneficial owner whose residential address matches the operating address covers the proof_of_address leg with their own per-UBO document, so a ubo_bank_statement alone completes the second route.

Conditionally required, driven by the profile's business and operations answers:

  • proof_of_licensure: required when operations.regulated_status is licensed. Reported as documents.proof_of_licensure.
  • ubo_source_of_funds: required when business.pre_revenue is true — see Pre-revenue businesses. Reported as documents.ubo_source_of_funds.

Everything else is optional supporting material. Reviewers may request specific extras during verification.

Pre-revenue businesses

proof_of_nature_of_business normally shows the business earning money from the activities it claims — invoices, executed agreements. A business that hasn't started earning yet has none of those, so upload whatever evidences its preparations to operate instead (a vendor or supplier agreement, a business plan) and set business.pre_revenue to true on the profile via PUT /org/kyb/profile:

{
  "business": {
    "pre_revenue": true
  }
}

The flag defaults to false, so nothing changes for a business that omits it. Setting it tells Seismic the document is deliberately alternative evidence, and Seismic passes that on to compliance review with the business description — so a pre-revenue entity isn't held up by a follow-up information request asking for the invoices it doesn't have.

The document itself is still required. pre_revenue changes what's appropriate to upload, not whether the slot must be filled.

A pre-revenue business is funded by its owners rather than by revenue, so two more things are enforced at submit when the flag is set:

  • operations.primary_source_of_funds must be private_capital, with operations.primary_source_of_funds_description describing that capital. Any other value is rejected with a violation on operations.primary_source_of_funds.
  • A ubo_source_of_funds document must be uploaded, showing where the funding owner's own money came from. When missing the validator reports the path documents.ubo_source_of_funds.

Seismic adds a statement to the supplemental information it sends to compliance review pointing at that evidence, so a reviewer reads the owner's documents as the business's source of funds.

KybDocumentRef

The metadata envelope every JSON endpoint returns. The bytes themselves are never inlined on this surface. Fetch them via GET /org/kyb/documents/:id.

FieldTypeNotes
document_idstring (UUID)Stable id. Use as the foreign key on associated_persons[].gov_id_*_image_document_id.
kindDocumentKindWhat the document represents.
filenamestringOriginal upload filename. Trimmed at 512 chars.
content_typestringMIME type the uploader supplied. Echoed back. Not re-sniffed.
size_bytesintegerExact byte count of the stored object.
descriptionstring | nullFree-text label supplied at upload. Present only for other documents. Omitted for every other kind.
uploaded_atstring (ISO-8601)Server clock at upload.

The submit pipeline picks the latest live document per (owner, kind) automatically when forwarding for compliance verification, so the slot's content is always current, you don't need to chase a fresh document_id after replacing a file. References to soft-deleted document_id values stored on the profile (e.g. associated_persons[].gov_id_front_image_document_id) won't break submit. The latest live row for that slot is still picked up.