Description
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 |