Skip to main content

Responding to an RFI

Each open RFI has two kinds of items: questions (free-text answers from the customer) and document requests (one or more files attached against a slot). Resolve every item and the case will close on the next review.

You can submit responses two ways:

  • Per-item — one HTTP call per question answer or per document attach. Easiest for incremental UIs.
  • Bulk — one HTTP call carrying every answer and attachment in a single batch. Atomic: if any item is invalid the whole batch is rejected (Error handling).

All endpoints require the standard AccountId and Authorization: Bearer <token> headers.


Answering a question

See the Answer an RFI question API reference for the full request/response schema.

curl -L -X POST 'https://sandbox-api.hubpay.io/v1/rfi/11111111-1111-1111-1111-111111111111/questions/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa/answer' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'AccountId: 058a2d45-139c-436b-8d1f-eec265e0f418' \
-H 'Authorization: Bearer <token>' \
-d '{
"answer": "Funds originate from the sale of investment property completed in March 2026."
}'

The response is the updated Rfi, so you can use it to refresh your local copy in one round trip. Re-submitting an answer to the same question replaces the previous answer. Once the case is closed or cancelled, further answer attempts return 409 CONFLICT (RFI_NOT_OPEN).


Attaching documents to a document request

Document responses are a two-step flow:

  1. Upload the file bytes via the RFI-specific upload endpoint POST /v1/rfi/{rfiId}/documents/upload. You get back a documentUploadId for each file.
  2. Attach one or more upload IDs to a specific document request on the RFI.

Step 1 — upload the file

curl -L -X POST 'https://sandbox-api.hubpay.io/v1/rfi/11111111-1111-1111-1111-111111111111/documents/upload' \
-H 'Content-Type: multipart/form-data' \
-H 'Accept: application/json' \
-H 'AccountId: 058a2d45-139c-436b-8d1f-eec265e0f418' \
-H 'Authorization: Bearer <token>' \
-F 'file=@"/path/to/bank-statement.pdf"'

The response carries the id of the upload — this is the documentUploadId you feed into the attach call below.

Step 2 — attach the upload to the document request

See the Attach documents API reference for the full request/response schema.

curl -L -X POST 'https://sandbox-api.hubpay.io/v1/rfi/11111111-1111-1111-1111-111111111111/document-requests/cccccccc-cccc-cccc-cccc-cccccccccccc/attach' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'AccountId: 058a2d45-139c-436b-8d1f-eec265e0f418' \
-H 'Authorization: Bearer <token>' \
-d '{
"documentUploadIds": [
"d1d1d1d1-d1d1-d1d1-d1d1-d1d1d1d1d1d1"
]
}'

Multi-file requirements (e.g. front + back of an ID) can be satisfied by passing multiple upload IDs in a single attach call. They merge into a single document, which is what gets reviewed and what subsequent webhooks reference.

The attach response is the updated Rfi. The documentRequests[] entry you just satisfied now has a non-null documentIdpersist this, see below.


Critical — persist documentId for webhook correlation

v1.rfi.document.* webhooks identify the document by the attached document's UUID, not the upload UUID you got from the upload endpoint. If you want to route an incoming v1.rfi.document.approved (or .declined / .validation_warnings) back to the originating RFI, you must persist a documentId → rfiId mapping.

Do not persist documentUploadId → rfiId

A common — and silently broken — pattern is to persist the upload ID from step 1. The webhook never carries that ID. Persist the documentId from the attach response (step 2) instead.

Pattern:

On attach response, for each entry in Rfi.documentRequests[]:
if entry.documentId is not null:
map[entry.documentId] = Rfi.id

On webhook arrival, look up event.data.documentId in the map to find the parent rfiId.

Each entry also exposes documentUploads[] — the same files surfaced as a list — so if you prefer to walk the file list, Rfi.documentRequests[].documentUploads[].id resolves to the same UUID as documentId. Either path populates the same map.


Submitting multiple responses in bulk

If your UI lets the customer answer everything at once and submit, the bulk endpoint avoids N round-trips. See the Submit RFI responses in bulk API reference for the full request/response schema.

curl -L -X POST 'https://sandbox-api.hubpay.io/v1/rfi/11111111-1111-1111-1111-111111111111/responses' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'AccountId: 058a2d45-139c-436b-8d1f-eec265e0f418' \
-H 'Authorization: Bearer <token>' \
-d '{
"answers": [
{
"questionId": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
"answer": "Funds originate from the sale of investment property completed in March 2026."
},
{
"questionId": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
"answer": "Yes — please find the latest audit report attached."
}
],
"attachments": [
{
"documentRequestId": "cccccccc-cccc-cccc-cccc-cccccccccccc",
"documentUploadIds": [
"d1d1d1d1-d1d1-d1d1-d1d1-d1d1d1d1d1d1"
]
}
]
}'

The bulk call is atomic — if any answer or attachment is invalid, the entire batch is rejected and no state changes. The response, on success, is the updated Rfi. Walk documentRequests[] and persist documentId → rfiId for the new entries exactly as you would for a per-item attach.


Replace semantics

ActionBehaviour
Re-answering a questionReplaces the previous answer in place.
Re-attaching to a satisfied document slotReplaces the previously attached document. The earlier document is retired and will not be reviewed.
Submitting once an item is APPROVEDReturns 409 CONFLICT (RFI_ITEM_ALREADY_APPROVED). Approved items are locked. See error handling.
Submitting once the case is closed/cancelledReturns 409 CONFLICT (RFI_NOT_OPEN). See error handling.

Refer to the API Reference for the full request/response schemas.