Skip to content

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

  1. The client creates a job object that manages the upload and validation workflow of a file to create a file object.
  2. The API returns the job object and the client uploads a file to the temporary presigned upload URL provided in the job object.
  3. The client polls the job object's status until the file has been uploaded and validated successfully to create a file object.
  4. If the upload failed, the client retrieves a result object from the job object to identify the reason for failure.

Retrieve file object flow

  1. The client retrieves a file object and creates a file download request
  2. The API returns a file object describing the file metadata and temporary presigned download URL.
  3. The client downloads the file from the file object's download URL.

Files objects definitions

The Files API defines the following standard objects for uploading, validation and downloading files:

  • Upload objects
  • Job objects
  • Result objects
  • File objects

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

NameTypeRequiredDescription
formatenumNoFile format. If omitted, defaults to csv.
compressionenumNoCompression applied to the uploaded file. If omitted, defaults to none.
sizeintegerYesFile size in bytes. The uploaded file must match this value.
sha256stringYesSHA-256 hash of the file, hex-encoded. The uploaded file must match this value.
validate_onlybooleanNoIf true, the uploaded file is processed in validation-only mode. If omitted, defaults to false.

Example

json
{
  "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

NameTypeDescription
job_idstringUnique identifier for the upload job.
statusenumCurrent job status.
createdtimestampUTC Unix timestamp when the upload job was created.
updatedtimestampUTC Unix timestamp when the upload job was last updated. null until the job state changes after creation.
completedtimestampUTC Unix timestamp when processing completed. null until the job reaches a terminal state.
validate_onlybooleanWhether the uploaded file is processed in validation-only mode. Defaults to false.
file_idstringUnique identifier for the file object being created by this job.
upload_urlstringTemporary presigned URL used to upload the file. null when the job can no longer accept the upload.
upload_url_expirestimestampUTC Unix timestamp when the upload URL expires. null when upload_url is null.
result_urlstringTemporary 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_expirestimestampUTC Unix timestamp when the result download URL expires. null when result_url is null.
result_sha256stringSHA-256 hash of the file returned by result_url, hex-encoded. null when result_url is null.

Status values

StatusDescription
readyUpload job created and ready to receive the file.
uploadingFile is being received.
processingFile is being validated and processed.
succeededFile was successfully processed.
failedFile 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

json
{
  "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

NameTypeDescription
job_idstringUnique identifier for the job associated with this result.
file_idstringUnique identifier for the file object associated with this result.
statusenumProcessing outcome, either succeeded or failed.
rows_processedintegerNumber of rows successfully processed.
rows_skippedintegerNumber of rows skipped during processing.
error_codestringTop-level file-level processing failure code. Present when status = failed.
errorsarray of objectsRow-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 codeMeaning
validation_failedOne or more rows failed validation and processing did not complete successfully.
upload_incompleteThe uploaded file was incomplete or could not be fully received.
job_expiredThe upload job expired before upload or processing completed.
file_hash_mismatchThe uploaded file did not match the supplied sha256 value.
file_size_mismatchThe uploaded file size did not match the supplied size value.
unsupported_schema_versionThe supplied schema_version is not supported for this upload workflow.
unsupported_formatThe supplied format is not supported for this upload workflow.
unsupported_compressionThe supplied compression is not supported for this upload workflow.
invalid_file_formatThe uploaded file could not be parsed as the declared format.
invalid_encodingThe uploaded file is not valid in the required character encoding.
missing_header_rowThe uploaded file does not contain the required header row.
invalid_headerThe header row is malformed or could not be interpreted.
missing_required_columnOne or more required columns are missing from the header row.
unknown_columnThe uploaded file contains one or more unsupported columns.
duplicate_columnThe uploaded file contains the same column more than once in the header row.
empty_fileThe uploaded file contains no data rows.
file_too_largeThe uploaded file exceeds the maximum allowed file size for the workflow.
row_limit_exceededThe uploaded file exceeds the maximum allowed row count for the workflow.
processing_failedThe 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:

NameTypeDescription
row_numberinteger1-based row number in the uploaded file, excluding the header row.
columnstringColumn name associated with the error, when applicable.
error_codestringMachine-readable row-level error code.
error_descriptionstringHuman-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 codeMeaning
missing_required_fieldA required field is missing or empty.
missing_conditional_fieldA field required by another field value is missing.
invalid_valueA field contains a syntactically invalid value that does not fit a more specific shared error code.
invalid_patternA field does not match the required pattern.
invalid_integerA field must be an integer but is not a valid integer.
invalid_decimalA field must be a decimal but is not a valid decimal.
invalid_timestampA field must be a valid timestamp but is not.
invalid_dateA field must be a valid date but is not.
invalid_enum_valueA field must be one of a defined set of values but is not.
invalid_urlA field must be a valid URL but is not.
invalid_booleanA field must be a valid boolean value but is not.
invalid_currency_codeA field must be a valid ISO 4217 currency code but is not.
invalid_country_codeA field must be a valid country code but is not.
value_too_longA field exceeds the maximum allowed length.
value_too_shortA field is shorter than the minimum allowed length.
value_out_of_rangeA numeric or date value falls outside the allowed range.
forbidden_characterA field contains one or more disallowed characters.
field_count_mismatchThe row has too many or too few fields compared with the header row.
duplicate_rowThe row duplicates another row in the file according to the workflow's row uniqueness rules.
duplicate_keyA field or field combination that must be unique appears more than once in the file.
unknown_referenceA field references an unknown identifier in a domain-defined reference set.

Success example

json
{
  "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

json
{
  "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

NameTypeDescription
file_idstringUnique identifier for the file.
createdtimestampUTC Unix timestamp when the file was ingested.
formatenumFile format. Value must be csv.
schema_versionstringVersion of the file schema used to validate and interpret the file.
compressionenumCompression applied to the file, either gzip or none.
sizeintegerFile size in bytes.
sha256stringSHA-256 hash of the file, hex-encoded.
download_urlstringTemporary presigned URL used to download the file. null when the file is not downloadable.
download_url_expirestimestampUTC 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

json
{
  "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
json
{
  "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
json
{
  "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
json
{
  "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
json
{
  "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

json
{
  "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:

json
{
  "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.format
  • file.compression
  • file.size
  • file.sha256
  • job.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

yaml
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: string

Error 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.

yaml
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.