Skip to main content

Upload Order Documents

Some services require supporting documents from the customer — for example a signed form or a photo ID. You can attach these to an order programmatically with the document-upload endpoint.

Uploaded documents are linked to the order for our fulfillment team and are surfaced back to you under the documents collection on the Get order response.

Upload a document

Send the request as multipart/form-data (not JSON):

POST {baseUrl}/orders/{order_uuid}/documents
Authorization: Bearer {token}
Content-Type: multipart/form-data
FieldTypeNotes
order_uuidstring (path)UUID of the order you are tracking (the parent order for a bundle).
filefileThe document. Accepted types: PDF, DOC, DOCX, JPG, PNG. Max size 25 MB.
field_keystring (optional)The exact key of a document-type input field from the service configuration this upload satisfies (see Required files below) — must name a real document field for this order's service, or the request 422s. If the key names a currently-required document field, it must also still have an open rejection (i.e. not already satisfied) when sent without rejection_id, or the request 422s. Omit entirely for a plain attachment not tied to any field; use description for a human-readable label instead. Only meaningful when this upload isn't answering a rejection — omit it whenever you send rejection_id, and the server derives it from the targeted rejection instead.
rejection_idinteger (optional)The id of an open rejection from required_actions.rejections (see Respond to order rejections) this upload should resolve — either a file request or a required document rejection. Sending it lets you omit field_key entirely for a required-document rejection — derived from the linked field's key. Required to resolve a file request — a file request has no field key, so an upload with no rejection_id never resolves one.
descriptionstring (optional)Free-text label for the document, up to 1000 characters. Distinct from field_key/rejection_id (which identify what the document answers) — not matched against any field or rejection, just stored and echoed back on this response and on Get order. Defaults to the staff-entered request text when this upload answers a file request and no description was sent.

Example with curl — a plain attachment, no rejection or field involved:

curl -X POST "{baseUrl}/orders/a1b2c3d4-e5f6-7890-abcd-ef1234567890/documents" \
-H "Authorization: Bearer {token}" \
-F "description=Driver License" \
-F "file=@/path/to/driver-license.pdf"

Answering a specific rejection instead — field_key is derived automatically once rejection_id is sent:

curl -X POST "{baseUrl}/orders/a1b2c3d4-e5f6-7890-abcd-ef1234567890/documents" \
-H "Authorization: Bearer {token}" \
-F "rejection_id=220742" \
-F "file=@/path/to/articles-of-organization.pdf"

Success

{
"data": {
"message": "Document uploaded successfully",
"order_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"document": {
"name": "driver-license.pdf",
"type": "general",
"field_key": null,
"description": "Driver License",
"uploaded_at": "2026-07-01"
},
"resolved_rejection_id": 220742
},
"success": true
}

document.type is always general on upload — reg_agent restriction is a CRM staff action taken afterwards. document.field_key is the matching service input field's key when this upload's field_key named a real document-type field; null for a plain attachment. document.description echoes back the description you sent, if any (or the staff-entered request text for a file request answered with no description).

resolved_rejection_id echoes back the rejection this upload resolved (file request or required document) — the rejection_id you sent, or the required-document rejection field_key matched. It is null for a plain attachment upload that answered no rejection, and always null for a file request unless you sent rejection_id.

Documents can be uploaded at any point in the order's lifecycle, as long as the order belongs to your partner account.

Because of this, document-type fields (e.g. state_specific.professional_license_document, state_specific.veteran_verification_document) must never be sent as values in the order create (POST /orders) or order update (PATCH /orders/{order_uuid}) body. Sending one is rejected with a 422 — one validation error per document field found, so a request with several inline document values gets every offending field back in a single response:

{
"success": false,
"message": "Validation failed",
"errors": {
"state_specific.professional_license_document": [
"Documents must be uploaded via POST /orders/{order_uuid}/documents, not included in the request body."
],
"state_specific.veteran_verification_document": [
"Documents must be uploaded via POST /orders/{order_uuid}/documents, not included in the request body."
]
}
}

Required files

Some services require a supporting file before they can be fulfilled. A required file is declared in the service configuration as an input field of type document with required: true

Because files are uploaded through this endpoint and never in the order-create body, a required file does not block order creation. Instead:

  1. When you create an order and a required file is missing, the order is automatically moved to Action Required, and an order_status_changed webhook is dispatched. The missing document is named in the order's required_actions as a rejection, with the same message guidance described in Respond to order rejections ("Upload the requested document via the documents EP to answer this rejection.").

  2. To satisfy the requirement, either:

    • Upload the file with field_key set to the required field's key, same as before this rejection got its own id — no rejection_id needed, as long as the requirement is still open (i.e. you haven't already satisfied it). Sending field_key for a required field that has nothing left to resolve — because it was already satisfied, or isn't actually missing — returns a 422 instead of silently accepting the upload, or
    • Upload the file with rejection_id set to that rejection's id and omit field_key entirely — the server derives it from the rejection automatically. If you send both, field_key must match the field's key or the request 422s.

    Each missing required file is tracked independently — if a service requires more than one file, the order stays in Action Required until every required file is uploaded.

  3. Once the last required file is uploaded, the order leaves Action Required and another order_status_changed webhook is dispatched.

For example, if the service configuration lists a required document field with "key": "formation_document", either of these resolves it:

# By field_key (no rejection_id needed)
curl -X POST "{baseUrl}/orders/a1b2c3d4-e5f6-7890-abcd-ef1234567890/documents" \
-H "Authorization: Bearer {token}" \
-F "field_key=formation_document" \
-F "file=@/path/to/formation-document.pdf"

# By rejection_id (field_key omitted — derived from the rejection)
curl -X POST "{baseUrl}/orders/a1b2c3d4-e5f6-7890-abcd-ef1234567890/documents" \
-H "Authorization: Bearer {token}" \
-F "rejection_id=220745" \
-F "file=@/path/to/formation-document.pdf"

For a field belonging to an array (each element requires its own document, e.g. beneficial_owners_data.*.id_document), use the indexed key from that specific rejection's field (see Get order), e.g. beneficial_owners_data.0.id_document — not the literal key with *.

Retrieving uploaded documents

The Get order response includes a documents array of the order's partner-visible documents:

"documents": [
{
"name": "driver-license.pdf",
"type": "general",
"field_key": null,
"description": null,
"uploaded_by": "customer",
"uploaded_at": "2026-07-01",
"download_url": "https://swyftfilings-docs.s3.amazonaws.com/documents/driver-license.pdf?X-Amz-Signature=..."
},
{
"name": "ra-agreement.pdf",
"type": "reg_agent",
"field_key": null,
"description": "Signed registered agent agreement",
"uploaded_by": "agent",
"uploaded_at": "2026-07-02",
"download_url": "https://swyftfilings-docs.s3.amazonaws.com/documents/ra-agreement.pdf?X-Amz-Signature=..."
}
]
  • A document is included when it's visible to everyone (type: "general") or restricted to the registered agent (type: "reg_agent") — internal-only documents are excluded.
  • field_key is the key of the service's document-type input field this document answers (e.g. state_specific.county_liquor_license_document), when it's related to one. Null for a plain attachment not tied to any input field.
  • description echoes back the free-text description sent at upload time, if any.
  • download_url is a short-lived signed link that expires 15 minutes after the response is generated. Download the file promptly, or request the order again to obtain a fresh link.
  • The array is empty ("documents": []) when no visible documents exist on the order.

Errors and edge cases

  • 422 Validation: file is missing, exceeds 25 MB, or is an unsupported type; field_key doesn't name a real document field for this order's service; field_key names a currently-required document field that no longer has an open rejection to resolve (already satisfied, or sent with no rejection_id for a requirement that isn't actually missing); field_key was sent alongside a rejection_id targeting a required-document rejection but doesn't match that field's key; or rejection_id was sent but does not match an open rejection eligible for document upload on this order (or one of its child lines).
  • 401 / 403: The order is not associated with your partner account.
  • Uploading a plain attachment (no field_key, no rejection_id) still succeeds (201) — it does not resolve any open file request. resolved_rejection_id is null in the response, and the file request stays open until you upload again with its rejection_id.