Description
Purpose and use
Uploads store documents and files needed by onboarding, KYB, KYC, QES, invoices, customer service, and profile workflows. They preserve evidence, approval state, signature status, and customer or record ownership.
Who uses this. Onboarding staff, compliance officers, customer service, document operations, and customers use uploads when submitting, reviewing, approving, or retrieving documents.
How it works. Each upload has a document type, record owner, customer scope, validation result, storage reference, and optional signature or approval state. Configured document types decide which files are accepted.
What users do. Users upload a document, review metadata and status, replace or patch allowed details, approve or reject where configured, and retrieve files for downstream workflows.
Outcomes and side effects. Uploads create customer evidence and can unblock KYB, QES, invoice OCR, avatar display, or customer support actions. They do not approve the parent process unless that workflow records completion.
Related manuals: KYB, QES, PDFGen, Invoices.
Overview
The Uploads API provides functionality for managing file uploads and documents:
- File upload and storage
- Document type management
- File validation
- Signature tracking
- Approval workflow
- Avatar management
- Customer document management
Core Concepts
Document Types
Document type codes are config-driven (uploads.documents in uploads.yaml). They are not a fixed API enum; invalid codes return 400 with uploads.invalid_document_type and an allowed_types parameter.
Common codes (deployment may add or omit keys):
| Code | Purpose |
|---|---|
bylaws | Bylaws with beneficiary information |
articles_of_association | Articles of association |
license | License documents |
customer_agreement | Customer agreement |
corporate_structure | Corporate structure |
declaration_of_shareholders | Declaration of shareholders |
statutes | Statutes or founding deed |
tariffs | Tariff documents |
account_statements | Account statements |
other | Other / uncategorized |
avatar | Avatar (dedicated avatar endpoints) |
Approval and signature status values are also defined under uploads.approval_status and uploads.signature_status in the same config file.
File Validation
- Supported formats: PDF, JPEG, PNG, JPG
- Size limits: 512 bytes (min) to 20MB (max)
- Content type validation
- File extension validation
Document Status
Approval Status
pending: Awaiting approvalapproved: Document approvedattached: No approval needed
Signature Status
pending: Awaiting signaturessigned: Document signednot_required: No signature needed
Avatar Types
customer: Customer avatarsuser: User avatars
Endpoints
File Management
Create File
POST /v1/uploads
Upload a new file.
Request Body:
{
"file_name": "customer_agreement.pdf",
"content": "base64_encoded_content",
"document_type": "customer_agreement",
"approval_needed": 1,
"approval_made": 0,
"signature_needed": 1,
"signature_made": 0,
"active": true,
"metadata": {
"department": "legal",
"priority": "high"
}
}Response:
{
"id": "uuid",
"file_name": "customer_agreement.pdf",
"document_type": "customer_agreement",
"approval_status": "pending",
"approval_needed": 1,
"approval_made": 0,
"signature_status": "pending",
"signature_needed": 1,
"signature_made": 0,
"content_length": 15360,
"file_extension": "application/pdf",
"active": true,
"metadata": {
"department": "legal",
"priority": "high",
"document_type_localized": "Customer Agreement",
"approval_status_localized": "Pending Approval",
"signature_status_localized": "Pending Signature"
},
"created_at": "2024-03-21T10:00:00Z",
"created_by": "uuid"
}Get All Files
GET /v1/uploads
List all files with optional filtering.
Query Parameters:
- isSigned: Filter signed documents
- isApproved: Filter approved documents
Get File
GET /v1/uploads/{id}
Get file metadata.
Get File Content
GET /v1/uploads/{id}/content
Get file content.
Response:
{
"file_name": "customer_agreement.pdf",
"content": "base64_encoded_content",
"file_extension": "application/pdf",
"document_type": "customer_agreement"
}Update File
PUT /v1/uploads/{id}
Replace upload metadata (file_name, approval/signature counts, active, metadata). To change document_type, use PATCH below.
Request Body:
{
"file_name": "updated_customer_agreement.pdf",
"approval_needed": 2,
"signature_needed": 2,
"metadata": {
"department": "legal",
"status": "revised"
},
"active": true
}Patch File Metadata
PATCH /v1/uploads/{id}
Change upload metadata partially. Use this to reclassify a document (document_type) without a full PUT body.
Request Body:
{
"document_type": "bylaws"
}document_type must be a valid code from uploads.documents in app config. The response includes updated document_type_localized and catalog icon in metadata.
Upload change history
GET /v1/uploads/{id}/history
Returns blame audit rows for one upload (create, update, delete, type change, signature adjustments). Requires read permission on the upload.
Customer upload history counts
GET /v1/uploads/customer/{customer_id}/history-counts
Returns { "counts": { "": , ... } } for uploads linked to the customer that the caller may read. Used by Configurator to show history icons without calling Internal-only /v1/blame/count.
Delete File
DELETE /v1/uploads/{id}
Delete a file.
Adjust Signature Count
PATCH /v1/uploads/{id}/signature
Increment or decrement the signature count (adjust_by). This is separate from PATCH /v1/uploads/{id}, which updates metadata such as document_type.
Request Body:
{
"adjust_by": 1
}Customer Document Management
Create Customer File
POST /v1/uploads/customer/{customer_id}
Upload a file for a specific customer. Requires update permission on the customers record identified by customer_id, plus create permission on uploads. The upload is linked to that customer; customer_id in the URL is authoritative (body cannot target another customer).
Get Customer Files
GET /v1/uploads/customer/{customer_id}
Get all files for a customer. Requires read permission on the customer, then returns only uploads linked to that customer that the caller may read.
Query Parameters:
- isSigned: Filter signed documents
- isApproved: Filter approved documents
- tag: Filter by document tag
Get Customer File By Type
GET /v1/uploads/customer/{customer_id}/file/type/{file_type}
Get customer files of a specific type.
Error Codes
Message keys are defined in (and related packages). API error responses use the wire code string (first column below), not Go constant names.
Upload module (uploads.*)
| Wire code | Go constant (errs) | Description |
|---|---|---|
uploads.failed_to_serialize | ErrMsgUploadFailedToSerialize | Failed to serialize upload data |
uploads.duplicate_entity | ErrMsgUploadDuplicateEntity | Duplicate upload exists |
uploads.unauthorized | ErrMsgUploadUnauthorized | Insufficient record or scoped access (upload/customer) |
uploads.database_error | ErrMsgUploadDatabaseError | Upload database operation failed |
uploads.record_not_found | ErrMsgUploadRecordNotFound | Upload record not found |
uploads.invalid_file_extension | ErrMsgUploadInvalidFileExtension | File extension or content type not allowed |
uploads.invalid_document_type | ErrMsgInvalidDocumentType | document_type not in uploads.documents config |
uploads.invalid_upload_input | ErrMsgInvalidUploadInput | Invalid or empty request/patch body |
uploads.failed_to_decode_data | ErrMsgUploadFailedToDecodeData | Failed to decode base64 file content |
uploads.file_too_large | ErrMsgUploadFileTooLarge | File exceeds configured max size |
uploads.file_too_small | ErrMsgUploadFileTooSmall | File below configured min size |
uploads.user_not_found | ErrMsgUploadUserNotFound | User not found (upload context) |
uploads.invalid_approval_status | ErrMsgInvalidApprovalStatus | Invalid approval status |
uploads.invalid_signature_status | ErrMsgInvalidSignatureStatus | Invalid signature status |
uploads.user_already_signed | ErrMsgUserAlreadySigned | User has already signed this document |
uploads.document_no_signature_count | ErrMsgNoSignatureCount | Document has no signature count |
uploads.upload_not_found | ErrMsgUploadNotFound | Upload not found (signature flow) |
uploads.approval_status_error | ErrMsgApprovalStatusError | Approval status transition error |
uploads.failed_to_fetch_upload | ErrMsgFailedToFetchUpload | Failed to load upload |
uploads.metadata_tag_required | ErrMsgUploadMetadataTagRequired | Customer file list metadata filter missing tag |
uploads.metadata_tag_invalid | ErrMsgUploadMetadataTagInvalid | Customer file list metadata tag must be a string array |
Related codes (other modules, used by uploads)
| Wire code | Go constant (errs) | Description |
|---|---|---|
customers_m.not_found | MsgCustomerNotFound | Customer not found |
customers.principal_not_found | MsgPrincipalNotFound | Customer principal not found |
common.forbidden | MsgForbidden | Forbidden (e.g. avatar owner access) |
rbac_m.failed_to_grant_access | MsgFailedToGrantAccess | Failed to grant record access after create |
Canonical modern scheduled transfer endpoint reserved for `CreateScheduledRequestV2` (`metadata`, not legacy `meta`). **Current behavior:** returns **501** until the scheduled-transfer execution worker exists. Use `POST /v2/transfers/finalize` for immediate execution today.
Upload a file for a specific customer. Requires update permission on the customer and create permission on uploads. `customer_id` in the path is authoritative; `document_type` must be a key from `uploads.documents` in config.