Files API
Confidential. Do not share without explicit permission.
The RSL Platform Files API describes the shared objects and patterns RSL Platform APIs uses to create, validate and retrieve structured file resources.
Introduction
RSL Platform APIs use bulk file exchange for high-volume workflows such as repertoire submission and report delivery. To keep those workflows predictable and consistent across APIs, this document defines a shared set of structured file resource upload, validation and download services.
Core concepts
The Files API is built around a small set of shared objects that work together across upload and download workflows.
Create file object flow
- The client creates a
jobobject that manages the upload and validation workflow of a file to create afileobject. - The API returns the
jobobject and the client uploads a file to the temporary presigned upload URL provided in thejobobject. - The client polls the
jobobject's status until the file has been uploaded and validated successfully to create a file object. - If the upload failed, the client retrieves a
resultobject from thejobobject to identify the reason for failure.
Retrieve file object flow
- The client retrieves a
fileobject and creates a file download request - The API returns a
fileobject describing the file metadata and temporary presigned download URL. - The client downloads the file from the
fileobject's download URL.
Files objects definitions
The Files API defines the following standard objects for uploading, validation and downloading files:
UploadobjectsJobobjectsResultobjectsFileobjects
RSL Platform APIs compose these objects into endpoint-specific request and response schemas, adding any resource-specific fields required by the endpoint.
The Upload object
An Upload object creates a job object to initiate a structured file upload and validation workflow.
Standard fields
| Name | Type | Required | Description |
|---|---|---|---|
format | enum | No | File format. If omitted, defaults to csv. |
compression | enum | No | Compression applied to the uploaded file. If omitted, defaults to none. |
size | integer | Yes | File size in bytes. The uploaded file must match this value. |
sha256 | string | Yes | SHA-256 hash of the file, hex-encoded. The uploaded file must match this value. |
validate_only | boolean | No | If true, the uploaded file is processed in validation-only mode. If omitted, defaults to false. |
Example
{
"upload": {
"format": "csv",
"schema_version": "1.0",
"compression": "gzip",
"size": 1048576,
"sha256": "d26b94ae60e4554c7333034960d2146f3801f42a7516a566a014a2f1e6d9c3b7",
"validate_only": false
}
}The Job object
A Job object represents the lifecycle and validation state of a structured file upload workflow and, if terminated successfully, creates a file object that represents the uploaded and validated file.
Standard fields
| Name | Type | Description |
|---|---|---|
job_id | string | Unique identifier for the upload job. |
status | enum | Current job status. |
created | timestamp | UTC Unix timestamp when the upload job was created. |
updated | timestamp | UTC Unix timestamp when the upload job was last updated. null until the job state changes after creation. |
completed | timestamp | UTC Unix timestamp when processing completed. null until the job reaches a terminal state. |
validate_only | boolean | Whether the uploaded file is processed in validation-only mode. Defaults to false. |
file_id | string | Unique identifier for the file object being created by this job. |
upload_url | string | Temporary presigned URL used to upload the file. null when the job can no longer accept the upload. |
upload_url_expires | timestamp | UTC Unix timestamp when the upload URL expires. null when upload_url is null. |
result_url | string | Temporary presigned URL used to download a file containing the result object when the job reaches a terminal state. null until the result is available. |
result_url_expires | timestamp | UTC Unix timestamp when the result download URL expires. null when result_url is null. |
result_sha256 | string | SHA-256 hash of the file returned by result_url, hex-encoded. null when result_url is null. |
Status values
| Status | Description |
|---|---|
ready | Upload job created and ready to receive the file. |
uploading | File is being received. |
processing | File is being validated and processed. |
succeeded | File was successfully processed. |
failed | File was rejected or could not be processed. |
A job enters uploading after the upload of the file begins and remains in that state until the file has been fully received. When a job reaches a terminal state (succeeded or failed), result_url references a temporary presigned URL to a file containing a result object for that job.
Example
{
"job": {
"job_id": "job_9aK2mQ7xT4vN8pR3cW6yZ1bD",
"status": "ready",
"created": 1760000000,
"updated": null,
"completed": null,
"validate_only": false,
"file_id": "file_R8nK3vT1qM6xP9cY4wL2dH7z",
"upload_url": "https://files.rslcollective.org/file_R8nK3vT1qM6xP9cY4wL2dH7z",
"upload_url_expires": 1760086400,
"result_url": null,
"result_url_expires": null,
"result_sha256": null
}
}The Result object
A Result object describes the status and outcome of a file upload and validation workflow.
Uploaded files are processed row by row. During processing, the platform may encounter file-level or row-level errors. Some errors abort processing immediately and cause the job to fail. Some row-level errors cause the affected row to be skipped and processing to continue.
RSL Platform APIs use the shared file-level and row-level error codes defined in this section wherever applicable, and may define additional file-level or row-level error codes for workflow-specific business rules.
Standard fields
| Name | Type | Description |
|---|---|---|
job_id | string | Unique identifier for the job associated with this result. |
file_id | string | Unique identifier for the file object associated with this result. |
status | enum | Processing outcome, either succeeded or failed. |
rows_processed | integer | Number of rows successfully processed. |
rows_skipped | integer | Number of rows skipped during processing. |
error_code | string | Top-level file-level processing failure code. Present when status = failed. |
errors | array of objects | Row-level processing errors. Present when one or more row-level errors were identified. |
File-level errors codes
The following file-level error_code values may be returned by upload job processing workflows:
| Error code | Meaning |
|---|---|
validation_failed | One or more rows failed validation and processing did not complete successfully. |
upload_incomplete | The uploaded file was incomplete or could not be fully received. |
job_expired | The upload job expired before upload or processing completed. |
file_hash_mismatch | The uploaded file did not match the supplied sha256 value. |
file_size_mismatch | The uploaded file size did not match the supplied size value. |
unsupported_schema_version | The supplied schema_version is not supported for this upload workflow. |
unsupported_format | The supplied format is not supported for this upload workflow. |
unsupported_compression | The supplied compression is not supported for this upload workflow. |
invalid_file_format | The uploaded file could not be parsed as the declared format. |
invalid_encoding | The uploaded file is not valid in the required character encoding. |
missing_header_row | The uploaded file does not contain the required header row. |
invalid_header | The header row is malformed or could not be interpreted. |
missing_required_column | One or more required columns are missing from the header row. |
unknown_column | The uploaded file contains one or more unsupported columns. |
duplicate_column | The uploaded file contains the same column more than once in the header row. |
empty_file | The uploaded file contains no data rows. |
file_too_large | The uploaded file exceeds the maximum allowed file size for the workflow. |
row_limit_exceeded | The uploaded file exceeds the maximum allowed row count for the workflow. |
processing_failed | The upload could not be processed due to an internal error. |
Row-level errors
An errors array contains row-level processing errors. Each error object contains:
| Name | Type | Description |
|---|---|---|
row_number | integer | 1-based row number in the uploaded file, excluding the header row. |
column | string | Column name associated with the error, when applicable. |
error_code | string | Machine-readable row-level error code. |
error_description | string | Human-readable description of the row-level error. |
Row-level error codes
The following row-level error_code values may be returned by upload job processing workflows:
| Error code | Meaning |
|---|---|
missing_required_field | A required field is missing or empty. |
missing_conditional_field | A field required by another field value is missing. |
invalid_value | A field contains a syntactically invalid value that does not fit a more specific shared error code. |
invalid_pattern | A field does not match the required pattern. |
invalid_integer | A field must be an integer but is not a valid integer. |
invalid_decimal | A field must be a decimal but is not a valid decimal. |
invalid_timestamp | A field must be a valid timestamp but is not. |
invalid_date | A field must be a valid date but is not. |
invalid_enum_value | A field must be one of a defined set of values but is not. |
invalid_url | A field must be a valid URL but is not. |
invalid_boolean | A field must be a valid boolean value but is not. |
invalid_currency_code | A field must be a valid ISO 4217 currency code but is not. |
invalid_country_code | A field must be a valid country code but is not. |
value_too_long | A field exceeds the maximum allowed length. |
value_too_short | A field is shorter than the minimum allowed length. |
value_out_of_range | A numeric or date value falls outside the allowed range. |
forbidden_character | A field contains one or more disallowed characters. |
field_count_mismatch | The row has too many or too few fields compared with the header row. |
duplicate_row | The row duplicates another row in the file according to the workflow's row uniqueness rules. |
duplicate_key | A field or field combination that must be unique appears more than once in the file. |
unknown_reference | A field references an unknown identifier in a domain-defined reference set. |
Success example
{
"result": {
"job_id": "job_9aK2mQ7xT4vN8pR3cW6yZ1bD",
"file_id": "file_f7Lp2Vx9qM4nT8rC3wK6yH1d",
"status": "succeeded",
"rows_processed": 48291,
"rows_skipped": 1,
"errors": [
{
"row_number": 3249,
"column": "scope_url",
"error_code": "invalid_url",
"error_description": "scope_url must be a valid URL."
}
]
}
}Failure example
{
"result": {
"job_id": "job_9aK2mQ7xT4vN8pR3cW6yZ1bD",
"file_id": "file_f7Lp2Vx9qM4nT8rC3wK6yH1d",
"status": "failed",
"error_code": "validation_failed",
"rows_processed": 14,
"rows_skipped": 0,
"errors": [
{
"row_number": 14,
"column": "publisher_id",
"error_code": "missing_required_field",
"error_description": "publisher_id is required."
}
]
}
}The File object
A File object represents a structured file including its metadata and download information. File objects are used to manage and download structured files through RSL Platform APIs.
Standard fields
| Name | Type | Description |
|---|---|---|
file_id | string | Unique identifier for the file. |
created | timestamp | UTC Unix timestamp when the file was ingested. |
format | enum | File format. Value must be csv. |
schema_version | string | Version of the file schema used to validate and interpret the file. |
compression | enum | Compression applied to the file, either gzip or none. |
size | integer | File size in bytes. |
sha256 | string | SHA-256 hash of the file, hex-encoded. |
download_url | string | Temporary presigned URL used to download the file. null when the file is not downloadable. |
download_url_expires | timestamp | UTC Unix timestamp when the download URL expires. null when download_url is null. |
Schema versioning
The schema_version field identifies the schema version used to validate and interpret the file. File schema versions are versioned independently of the API URL version and independently of other file types used by the same API.
Schema versions are expressed as dot-separated numeric version strings in the form MAJOR.MINOR, for example 1.0, 1.1, or 2.0.
Example
{
"file": {
"file_id": "file_f7Lp2Vx9qM4nT8rC3wK6yH1d",
"created": 1774224000,
"format": "csv",
"schema_version": "1.0",
"compression": "gzip",
"size": 1048576,
"sha256": "d26b94ae60e4554c7333034960d2146f3801f42a7516a566a014a2f1e6d9c3b7",
"download_url": "https://files.rslcollective.org/file_f7Lp2Vx9qM4nT8rC3wK6yH1d.csv.gz",
"download_url_expires": 1760086400
}
}Examples
The Files API uses the shared objects above in a small number of common wire-level patterns.
Create a file
To upload a file, the client creates a file object using two helper objects: an upload object to initiate the upload and validation workflow, and a job object to track the workflow status and retrieve the result.
Create a job
The client creates a job object by submitting an upload object that defines the file metadata.
Example request
{
"upload": {
"format": "csv",
"schema_version": "1.0",
"compression": "gzip",
"size": 1048576,
"sha256": "d26b94ae60e4554c7333034960d2146f3801f42a7516a566a014a2f1e6d9c3b7",
"validate_only": false
}
}File upload
The API returns a job helper object that manages the upload and validation workflow used to create the file object. The client completes the workflow by sending the file bytes to job.upload_url over HTTPS and then polling until the job reaches a terminal state.
Example response
{
"job": {
"job_id": "job_9aK2mQ7xT4vN8pR3cW6yZ1bD",
"status": "ready",
"created": 1760000000,
"updated": null,
"completed": null,
"validate_only": false,
"file_id": "file_f7Lp2Vx9qM4nT8rC3wK6yH1d",
"upload_url": "https://files.rslcollective.org/file_f7Lp2Vx9qM4nT8rC3wK6yH1d",
"upload_url_expires": 1760086400,
"result_url": null,
"result_url_expires": null,
"result_sha256": null
}
}File upload status
The client can poll the status of file upload by retrieving the job object.
Example response
{
"job": {
"job_id": "job_9aK2mQ7xT4vN8pR3cW6yZ1bD",
"status": "failed",
"created": 1774225000,
"updated": 1774226200,
"completed": 1774226200,
"validate_only": false,
"file_id": "file_f7Lp2Vx9qM4nT8rC3wK6yH1d",
"upload_url": null,
"upload_url_expires": null,
"result_url": "https://files.rslcollective.org/file_R8nK3vT1qM6xP9cY4wL2dH7z.json",
"result_url_expires": 1774312600,
"result_sha256": "f26b94ae60e4554c7333034960d2146f3801f42a7516a566a014a2f1e6d9c3b9"
}
}Result response
After the job reaches a terminal state, the job.result_url field provides a link to a file containing a result object describing the outcome of the upload and validation workflow.
Example result
{
"result": {
"job_id": "job_9aK2mQ7xT4vN8pR3cW6yZ1bD",
"file_id": "file_f7Lp2Vx9qM4nT8rC3wK6yH1d",
"status": "succeeded",
"rows_processed": 100,
"rows_skipped": 0
}
}Retrieve a file
To download a file, the client retrieves a file object that provides the file metadata and temporary presigned download URL.
Example response
{
"file": {
"file_id": "file_f7Lp2Vx9qM4nT8rC3wK6yH1d",
"created": 1774224000,
"format": "csv",
"schema_version": "1.0",
"compression": "gzip",
"size": 1048576,
"sha256": "d26b94ae60e4554c7333034960d2146f3801f42a7516a566a014a2f1e6d9c3b7",
"download_url": "https://files.rslcollective.org/file_f7Lp2Vx9qM4nT8rC3wK6yH1d.csv.gz",
"download_url_expires": 1759160400
}
}File transfers
Interrupted uploads and downloads
If a file upload or download is interrupted, the client should retry the same URL while the URL remains valid. Temporary download URLs support HTTP byte range requests, so clients can resume interrupted downloads without restarting the transfer.
If the URL has expired, the client must create a new job or retrieve a new file object through the applicable API endpoint.
Serial upload workflows
A file object creation workflow allows only one non-terminal job at a time. If the client tries to create a new job while another job for the same workflow is still in ready, uploading, or processing, the API returns 409 Conflict and the following error response:
{
"error": "upload_job_in_progress",
"error_description": "An upload job is already in progress."
}After the current job reaches succeeded or failed, or after it expires, the client can create a new job for that workflow.
Job expiration
Non-terminal jobs expire automatically if they do not reach a terminal state within the time limit defined by job.upload_url_expires. After a job expires or reaches a terminal state, the client may create a new job.
Temporary URLs
The files API uses temporary presigned URLs for uploading and downloading files. These URLs provide time-limited access to a specific file, expire at the time indicated by the corresponding expiration timestamp, and may be refreshed by calling the applicable API endpoint again while the file remains available.
Temporary upload and download URLs remain valid for at least the minimum interval defined by the applicable API specification.
File integrity and authoritative metadata
Clients must use the metadata returned by the API as the authoritative description of the file. This includes:
file.formatfile.compressionfile.sizefile.sha256job.result_sha256
Clients should not rely on HTTP Content-Type or Content-Encoding headers returned by a temporary download URL as the authoritative indicator of file format or compression.
File transfer security
All API requests and file transfers must be made over HTTPS, and calls made over plain HTTP will fail. Files exchanged through RSL Platform APIs are encrypted at rest using server-side encryption with cloud-managed keys.
Appendix: Machine-readable shared schemas
This appendix defines the shared OpenAPI schema fragments used by RSL Platform APIs for file transfer and asynchronous processing workflows.
OpenAPI definition
components:
schemas:
Upload:
type: object
required: [schema_version, size, sha256]
properties:
format:
type: string
enum: [csv]
default: csv
schema_version:
type: string
compression:
type: string
enum: [gzip, none]
default: none
size:
type: integer
minimum: 0
sha256:
type: string
pattern: "^[A-Fa-f0-9]{64}$"
validate_only:
type: boolean
default: false
Job:
type: object
required:
- job_id
- status
- created
- updated
- completed
- validate_only
- file_id
- upload_url
- upload_url_expires
- result_url
- result_url_expires
- result_sha256
properties:
job_id:
type: string
status:
type: string
enum: [ready, uploading, processing, succeeded, failed]
created:
type: integer
updated:
type: integer
nullable: true
completed:
type: integer
nullable: true
validate_only:
type: boolean
default: false
file_id:
type: string
upload_url:
type: string
format: uri
nullable: true
upload_url_expires:
type: integer
nullable: true
result_url:
type: string
format: uri
nullable: true
result_url_expires:
type: integer
nullable: true
result_sha256:
type: string
pattern: "^[A-Fa-f0-9]{64}$"
nullable: true
File:
type: object
required:
- file_id
- created
- format
- schema_version
- compression
- size
- sha256
- download_url
- download_url_expires
properties:
file_id:
type: string
created:
type: integer
format:
type: string
enum: [csv]
schema_version:
type: string
compression:
type: string
enum: [gzip, none]
size:
type: integer
minimum: 0
sha256:
type: string
pattern: "^[A-Fa-f0-9]{64}$"
download_url:
type: string
format: uri
nullable: true
download_url_expires:
type: integer
nullable: true
Result:
oneOf:
- $ref: "#/components/schemas/ResultSuccess"
- $ref: "#/components/schemas/ResultFailure"
ResultSuccess:
type: object
required: [job_id, file_id, status, rows_processed, rows_skipped]
properties:
job_id:
type: string
file_id:
type: string
status:
type: string
enum: [succeeded]
rows_processed:
type: integer
minimum: 0
rows_skipped:
type: integer
minimum: 0
errors:
type: array
items:
$ref: "#/components/schemas/ResultRowError"
ResultFailure:
type: object
required: [job_id, file_id, status, error_code, rows_processed, rows_skipped]
properties:
job_id:
type: string
file_id:
type: string
status:
type: string
enum: [failed]
error_code:
type: string
enum:
- validation_failed
- upload_incomplete
- upload_job_in_progress
- job_expired
- file_hash_mismatch
- file_size_mismatch
- unsupported_schema_version
- unsupported_format
- unsupported_compression
- invalid_file_format
- invalid_encoding
- missing_header_row
- invalid_header
- missing_required_column
- unknown_column
- duplicate_column
- empty_file
- file_too_large
- row_limit_exceeded
- processing_failed
rows_processed:
type: integer
minimum: 0
rows_skipped:
type: integer
minimum: 0
errors:
type: array
items:
$ref: "#/components/schemas/ResultRowError"
ResultRowError:
type: object
required: [row_number, error_code]
properties:
row_number:
type: integer
minimum: 1
column:
type: string
error_code:
type: string
enum:
- missing_required_field
- missing_conditional_field
- invalid_value
- invalid_pattern
- invalid_integer
- invalid_decimal
- invalid_timestamp
- invalid_date
- invalid_enum_value
- invalid_url
- invalid_boolean
- invalid_currency_code
- invalid_country_code
- value_too_long
- value_too_short
- value_out_of_range
- forbidden_character
- field_count_mismatch
- duplicate_row
- duplicate_key
- unknown_reference
- inconsistent_row
- mutually_exclusive_fields
error_description:
type: stringError catalog
This catalog defines the machine-readable error codes used by this specification. API error responses use the generic Error schema defined in the OpenAPI definition.
catalog_type: rsl.files_api.error_catalog
catalog_version: 1.0.0-beta
file_errors:
- code: validation_failed
category: file
retryable: false
description: One or more rows failed validation and processing did not complete successfully.
- code: upload_incomplete
category: file
retryable: true
description: The uploaded file was incomplete or could not be fully received.
- code: upload_job_in_progress
category: file
retryable: true
description: A non-terminal upload job is already in progress for the workflow.
- code: job_expired
category: file
retryable: true
description: The upload job expired before upload or processing completed.
- code: file_hash_mismatch
category: file
retryable: false
description: The uploaded file did not match the supplied sha256 value.
- code: file_size_mismatch
category: file
retryable: false
description: The uploaded file size did not match the supplied size value.
- code: unsupported_schema_version
category: file
retryable: false
description: The supplied schema_version is not supported for this upload workflow.
- code: unsupported_format
category: file
retryable: false
description: The supplied format is not supported for this upload workflow.
- code: unsupported_compression
category: file
retryable: false
description: The supplied compression is not supported for this upload workflow.
- code: invalid_file_format
category: file
retryable: false
description: The uploaded file could not be parsed as the declared format.
- code: invalid_encoding
category: file
retryable: false
description: The uploaded file is not valid in the required character encoding.
- code: missing_header_row
category: file
retryable: false
description: The uploaded file does not contain the required header row.
- code: invalid_header
category: file
retryable: false
description: The header row is malformed or could not be interpreted.
- code: missing_required_column
category: file
retryable: false
description: One or more required columns are missing from the header row.
- code: unknown_column
category: file
retryable: false
description: The uploaded file contains one or more unsupported columns.
- code: duplicate_column
category: file
retryable: false
description: The uploaded file contains the same column more than once in the header row.
- code: empty_file
category: file
retryable: false
description: The uploaded file contains no data rows.
- code: file_too_large
category: file
retryable: false
description: The uploaded file exceeds the maximum allowed file size for the workflow.
- code: row_limit_exceeded
category: file
retryable: false
description: The uploaded file exceeds the maximum allowed row count for the workflow.
- code: processing_failed
category: file
retryable: true
description: The upload could not be processed due to an internal error.
row_errors:
- code: missing_required_field
category: row
retryable: false
description: A required field is missing or empty.
- code: missing_conditional_field
category: row
retryable: false
description: A field required by another field value is missing.
- code: invalid_value
category: row
retryable: false
description: A field contains a syntactically invalid value that does not fit a more specific shared error code.
- code: invalid_pattern
category: row
retryable: false
description: A field does not match the required pattern.
- code: invalid_integer
category: row
retryable: false
description: A field must be an integer but is not a valid integer.
- code: invalid_decimal
category: row
retryable: false
description: A field must be a decimal but is not a valid decimal.
- code: invalid_timestamp
category: row
retryable: false
description: A field must be a valid timestamp but is not.
- code: invalid_date
category: row
retryable: false
description: A field must be a valid date but is not.
- code: invalid_enum_value
category: row
retryable: false
description: A field must be one of a defined set of values but is not.
- code: invalid_url
category: row
retryable: false
description: A field must be a valid URL but is not.
- code: invalid_boolean
category: row
retryable: false
description: A field must be a valid boolean value but is not.
- code: invalid_currency_code
category: row
retryable: false
description: A field must be a valid ISO 4217 currency code but is not.
- code: invalid_country_code
category: row
retryable: false
description: A field must be a valid country code but is not.
- code: value_too_long
category: row
retryable: false
description: A field exceeds the maximum allowed length.
- code: value_too_short
category: row
retryable: false
description: A field is shorter than the minimum allowed length.
- code: value_out_of_range
category: row
retryable: false
description: A numeric or date value falls outside the allowed range.
- code: forbidden_character
category: row
retryable: false
description: A field contains one or more disallowed characters.
- code: field_count_mismatch
category: row
retryable: false
description: The row has too many or too few fields compared with the header row.
- code: duplicate_row
category: row
retryable: false
description: The row duplicates another row in the file according to the workflow's row uniqueness rules.
- code: duplicate_key
category: row
retryable: false
description: A field or field combination that must be unique appears more than once in the file.
- code: unknown_reference
category: row
retryable: false
description: A field references an unknown identifier in a domain-defined reference set.
- code: inconsistent_row
category: row
retryable: false
description: The row contains values that are inconsistent with each other.
- code: mutually_exclusive_fields
category: row
retryable: false
description: The row contains two or more fields that cannot be provided together.Changelog
- 2026-03-30: Initial draft.
