Skip to content
Logo

Requests for information

When a verification needs something the submitted profile didn't provide, Seismic compliance raises a request for information (RFI) against it: a short list of specific asks, emailed to the org's compliance address and readable here.

Every item is answered through the answers endpoints, with a written answer, a document already uploaded for the subject, or both. Each answer closes only the item it answers, and a request reads as answered once every one of its items has an answer; the answers are then reviewed, and any profile change they support is made as part of that review rather than by the answer itself.

Endpoints, one pair per subject:

The reads return the same body, and both are the same data the hosted verification form shows in its "Pending RFIs" step.

GET /customers/:id/kyc/rfis

Open requests on one customer's verification — KYC for individuals, KYB for businesses.

Response 200

{
  "rfis": [
    {
      "id": "3f1c…",
      "sent_at": "2026-09-10T14:02:11.000Z",
      "items": [
        {
          "item_index": 0,
          "text": "Please provide the residential street address.",
          "kind": "other"
        },
        {
          "item_index": 1,
          "text": "Please upload a bank statement from the last 3 months.",
          "kind": "document"
        },
        {
          "item_index": 2,
          "text": "Please upload a diagram showing the entity's complete transaction flow.",
          "kind": "document",
          "document_kind": "flow_of_funds"
        }
      ]
    }
  ],
  "answered": []
}
FieldTypeNotes
rfisarrayOpen requests, oldest first. Empty when nothing is outstanding.
answeredarrayRequests already answered, newest first — a read-only history of the questions and the answers given. See Answered history.
idstringRequest id. Stable for the life of the request.
sent_atstringOptional. ISO-8601 timestamp of when the request went out. Absent on a request that has been raised but not yet sent.
itemsarrayThe individual asks. Always at least one.

Each entry in items:

FieldTypeNotes
item_indexnumberPosition of the item within the request. Quote it back when answering.
textstringThe request, written for the person completing the form. Free-form — render it, don't parse it.
kindenumdocument | other. A hint about the expected answer: a document upload, or a written answer. Every item accepts either or both.
document_kindstringOptional. The document slot an upload answering this item fills, as a document kind slug. Upload the file under this kind so it lands in place. Present only when the request names a slot.
person_namestringOptional. The associated person the request concerns, when it concerns one.

Errors

CodeStatusMeaning
Unauthorized401Missing or invalid API key.
CustomerNotFound404No such customer in this org.

GET /org/kyb/rfis

Open requests on the org's own KYB, the counterpart of the per-customer read. Same response body.

An org that has not saved a KYB profile yet has no verification to hold a request against, so it returns an empty rfis array rather than a 404 — a sweep doesn't have to special-case the org that hasn't started.

curl https://api.seismic.io/v0/org/kyb/rfis \
  -H "Authorization: Bearer $SEISMIC_API_KEY"

Answered history

answered is the read-only record the hosted verification form shows as RFI Log: for every request with answered items, each question as it was asked and the latest answer on record. It stays readable at every status, including after the verification is decided, and is never editable — a new answer supersedes rather than rewrites.

{
  "rfis": [],
  "answered": [
    {
      "id": "3f1c…",
      "sent_at": "2026-09-10T14:02:11.000Z",
      "items": [
        {
          "question": "Please explain the purpose of the incoming transfers.",
          "answer": "Monthly retainer payments under an ongoing design contract.",
          "answered_at": "2026-09-12T09:15:40.000Z"
        },
        {
          "question": "Please upload a bank statement from the last 3 months.",
          "document_id": "9a4e…",
          "document_filename": "statement-2026-08.pdf",
          "answered_at": "2026-09-12T09:15:40.000Z"
        }
      ]
    }
  ]
}

Each entry in items carries answer, document_id, or both, depending on how the item was answered. document_id is the document as it is on record now — the upload itself, or the document it was filed as during review — and opens through the documents endpoints. Once no copy remains, document_id is omitted and only document_filename is kept.

Answering items

Answers are recorded in place, against the request and item they answer:

  • POST /customers/:id/kyc/rfis/answers — one customer's requests.
  • POST /org/kyb/rfis/answers — the org's own KYB requests.

A document answer references a document already uploaded for the same subject through the documents endpoints. Each answer names the request and the item it answers:

{
  "answers": [
    {
      "rfi_id": "3f1c…",
      "item_index": 0,
      "answer": "The March deposit was the proceeds of a company vehicle sale."
    },
    {
      "rfi_id": "3f1c…",
      "item_index": 1,
      "document_id": "9a4e…"
    }
  ]
}
FieldTypeNotes
answersarrayAt least one answer.
rfi_idstringThe open request's id, from the read above.
item_indexnumberThe answered item's item_index, from the read above.
answerstringOptional when document_id is given. The written answer, at most 10,000 characters.
document_idstringOptional when answer is given. Id of a document uploaded for this subject that answers the item.

Response 200

{
  "recorded": 1,
  "supplemental_entries": [
    {
      "id": "5b5b5b5b-5b5b-4b5b-8b5b-5b5b5b5b5b5b",
      "kind": "document",
      "description": "Please provide a bank statement covering the last three months.",
      "document_id": "9a4e4e4e-4e4e-4e4e-8e4e-4e4e4e4e4e4e"
    }
  ]
}

recorded counts the answers newly recorded; an answer identical to the latest recorded one for the same item is acknowledged without being recorded again.

A document supplied in an answer is carried with the profile from then on. One uploaded under a structured kind, such as proof_of_address, has already replaced the profile's document of that kind. One uploaded under the catch-all other kind has no slot of its own, so it is placed during review: the reviewer either moves it into the slot it belongs in, replacing the document there, or files it in the profile's supplemental section under a title saying what the document is. supplemental_entries lists any entries filed by this call itself, which happens only when no review will place the document: each carries the item it answers as its description, so the entry passes the section's submit rules as filed. A document the section already attaches is not filed again. A later profile PUT replaces the section in full, so include filed entries in it to keep them.

Each answer closes only the item it answers. Items left out of a call stay in the open list, and pending_rfi stays true, until they are answered too. Written answers are kept verbatim on the verification's record for compliance review, and any profile change they support is made during that review.

Errors

CodeStatusMeaning
InvalidRequest400Empty batch, an answer with neither answer nor document_id, blank or oversized text, or an unknown item_index.
Unauthorized401Missing or invalid API key.
NotFound404No such request on this subject, or no such document.
—409The request is no longer open.

When requests are visible

A request stays readable while the verification can still act on it, and disappears once it can't:

  • It is answered. Submitting the profile again — or recording answers through the answers endpoint — answers every open request on it. The request leaves this list on the next read, whether or not the answer actually covered what was asked.
  • The verification is decided. An approval, a rejection, or a hold supersedes every open request — a decided verification has nothing outstanding.

Relationship to pending_rfi

GET /customers returns a pending_rfi boolean per row, and GET /customers/:id/kyc/state returns one for a single customer. It is exactly rfis being non-empty, derived from the same rule above — use it to find which customers to read requests for, then call this endpoint for the detail.

Filter the list on it directly to sweep for work:

curl "https://api.seismic.io/v0/customers?pending_rfi=true&limit=100" \
  -H "Authorization: Bearer $SEISMIC_API_KEY"

Polling

There is no webhook for a raised request today. pending_rfi on the filtered customer list is the intended signal: one call per sweep returns only the customers with something outstanding, so the cost doesn't grow with the size of your customer base.