Submitting Data
The V3 submission endpoint supports deferred file uploads, allowing you to submit form data first and upload files separately using presigned S3 URLs. File fields can be submitted at the root level (for the primary customer record) or within role-entity submissions (for associated entities), or both.
Integration Flow
- Submit form data with file names (not file content)
- Receive presigned URLs for each file that needs uploading
- Upload files to S3 using the presigned URLs
- Confirm the submission to verify uploads and resume execution
Step 1: Submit Form Data
Submit your form data including file field values as filenames (strings). The endpoint accepts file fields at the root level, within role-entity arrays, or both simultaneously.
Endpoint: POST /v3/public/actions/{token}
Example: Root-Level Submission with Files
Use this when the form collects files for the primary customer record directly.
{
"first_name": "John",
"last_name": "Smith",
"date_of_birth": "1985-03-15",
"id_document": "passport_scan.pdf",
"proof_of_address": "utility_bill.pdf"
}Example: Role-Entity Submission with Files
Use this when the form collects files for multiple related entities.
Important: Each
referencevalue must be unique across all client records in the workspace, not just within a single submission. If areferencematches an existing client record, the request will be rejected with a400error (DUPLICATE_REFERENCE). Use globally unique identifiers (e.g., UUIDs or prefixed IDs) to avoid collisions.
{
"role-entity": [
{
"reference": "company_reference_id_1",
"customer_type": "company",
"company_name": "Acme Corporation",
"registration_number": "12345678",
"company_document": "registration_certificate.pdf"
},
{
"reference": "owner_reference_id_1",
"customer_type": "individual",
"first_name": "John",
"last_name": "Smith",
"id_document": "passport_scan.pdf"
}
],
"role-entity_relations": [
{
"from": "company_reference_id_1",
"to": "root",
"role": "owner"
},
{
"from": "owner_reference_id_1",
"to": "company_reference_id_1",
"role": "ubo",
"ownership_percentage": 75
}
]
}Example: Combined Root-Level and Role-Entity Files
You can submit files at both levels in a single request. Root-level files attach to the primary customer record, while role-entity files attach to their respective entities.
{
"company_document": "main_registration.pdf",
"role-entity": [
{
"reference": "director_ref_1",
"customer_type": "individual",
"first_name": "Jane",
"last_name": "Doe",
"id_document": "director_passport.pdf"
}
],
"role-entity_relations": [
{
"from": "director_ref_1",
"to": "root",
"role": "director"
}
]
}Response (status: accepted)
When files need uploading, you receive presigned URLs. Root-level files omit the entityReference field, while role-entity files include it to identify which entity the file belongs to.
Root-level files response:
{
"status": "accepted",
"fileUploads": [
{
"fileName": "passport_scan.pdf",
"spektrDataField": "id_document",
"url": "https://s3.eu-north-1.amazonaws.com/bucket-name",
"fields": {
"key": "workspace-id/endClient/record-id/passport_scan.pdf",
"Content-Type": "application/pdf",
"X-Amz-Algorithm": "AWS4-HMAC-SHA256",
"X-Amz-Credential": "...",
"X-Amz-Date": "20260203T120000Z",
"Policy": "eyJ...",
"X-Amz-Signature": "..."
}
},
{
"fileName": "utility_bill.pdf",
"spektrDataField": "proof_of_address",
"url": "https://s3.eu-north-1.amazonaws.com/bucket-name",
"fields": {
"key": "workspace-id/endClient/record-id/utility_bill.pdf",
"Content-Type": "application/pdf",
"X-Amz-Algorithm": "AWS4-HMAC-SHA256",
"X-Amz-Credential": "...",
"X-Amz-Date": "20260203T120000Z",
"Policy": "eyJ...",
"X-Amz-Signature": "..."
}
}
]
}Role-entity files response:
{
"status": "accepted",
"fileUploads": [
{
"entityReference": "company_reference_id_1",
"fileName": "registration_certificate.pdf",
"spektrDataField": "company_document",
"url": "https://s3.eu-north-1.amazonaws.com/bucket-name",
"fields": {
"key": "workspace-id/endClient/entity-id-1/registration_certificate.pdf",
"Content-Type": "application/pdf",
"X-Amz-Algorithm": "AWS4-HMAC-SHA256",
"X-Amz-Credential": "...",
"X-Amz-Date": "20260203T120000Z",
"Policy": "eyJ...",
"X-Amz-Signature": "..."
}
},
{
"entityReference": "owner_reference_id_1",
"fileName": "passport_scan.pdf",
"spektrDataField": "id_document",
"url": "https://s3.eu-north-1.amazonaws.com/bucket-name",
"fields": {
"key": "workspace-id/endClient/entity-id-2/passport_scan.pdf",
"Content-Type": "application/pdf",
"X-Amz-Algorithm": "AWS4-HMAC-SHA256",
"X-Amz-Credential": "...",
"X-Amz-Date": "20260203T120000Z",
"Policy": "eyJ...",
"X-Amz-Signature": "..."
}
}
]
}Response (status: completed)
When no files need uploading:
{
"status": "completed"
}Step 2: Upload Files to S3
For each file in the fileUploads array, send a multipart/form-data POST request to the presigned URL.
Important: Include all
fieldsas form fields before the file content.
Example: cURL
curl -X POST "https://s3.eu-north-1.amazonaws.com/bucket-name" \
-F "key=workspace-id/endClient/record-id/passport_scan.pdf" \
-F "Content-Type=application/pdf" \
-F "X-Amz-Algorithm=AWS4-HMAC-SHA256" \
-F "X-Amz-Credential=..." \
-F "X-Amz-Date=20260203T120000Z" \
-F "Policy=eyJ..." \
-F "X-Amz-Signature=..." \
-F "file=@/path/to/passport_scan.pdf"Example: JavaScript/TypeScript
interface FileUploadInfo {
entityReference?: string;
fileName: string;
spektrDataField: string;
url: string;
fields: Record<string, string>;
}
async function uploadToS3(fileUpload: FileUploadInfo, fileContent: File | Blob) {
const formData = new FormData();
// Add all presigned fields BEFORE the file
Object.entries(fileUpload.fields).forEach(([key, value]) => {
formData.append(key, value);
});
// Add the file content last
formData.append('file', fileContent, fileUpload.fileName);
const response = await fetch(fileUpload.url, {
method: 'POST',
body: formData,
});
if (!response.ok) {
throw new Error(`Upload failed: ${response.status}`);
}
return response;
}Step 3: Confirm Submission
After uploading all files, confirm the submission to verify uploads and resume process execution.
Endpoint: POST /v3/public/actions/{token}/confirm
Success Response (200)
{
"status": "completed"
}Missing Files Response (409 Conflict)
If any files are missing from S3, you'll receive new presigned URLs:
{
"status": "pending",
"fileUploads": [
{
"entityReference": "owner_reference_id_1",
"fileName": "passport_scan.pdf",
"spektrDataField": "id_document",
"url": "https://s3.eu-north-1.amazonaws.com/bucket-name",
"fields": { ... }
}
]
}Upload the missing files and call /confirm again.
Field Reference
| Field | Description |
|---|---|
reference | A unique identifier for the entity within role-entity. Must be unique across all client records in the workspace — a duplicate will cause the request to fail with a 400 error (DUPLICATE_REFERENCE). |
entityReference | Identifies which entity the file belongs to (matches reference in role-entity). Only present for role-entity files; omitted for root-level files. |
spektrDataField | The field name for the file (e.g., company_document, id_document) |
fileName | The original filename provided in the submission |
url | The S3 presigned URL to POST the file to |
fields | Form fields that must be included in the multipart upload |
Error Handling
| Status | Meaning | Action |
|---|---|---|
200 with status: completed | No files to upload | Done |
200 with status: accepted | Files need uploading | Upload files, then call /confirm |
400 | Validation error | Check error message, fix data |
401 | Token expired/invalid | Restart the flow |
409 on /confirm | Files missing in S3 | Re-upload missing files using new URLs |
500 | Server error | Retry or contact support |
Best Practices
- Always check the response status - Handle both
completedandacceptedcases - Include all fields before file - S3 presigned POST requires form fields before the file content
- Implement retry logic - The
/confirmendpoint provides new presigned URLs if uploads fail - Check for
entityReference- Use it to associate files with the correct entity; its absence indicates a root-level file - Handle timeouts - Presigned URLs expire (typically 1 hour), so upload promptly after submission
Updated 21 days ago