Skip to content

Files API

Confidential. Do not share without explicit permission.

Introduction

The RSL Platform Files API describes the shared objects and patterns RSL Platform APIs use to create, validate and retrieve structured file resources. RSL Platform APIs compose these objects into endpoint-specific request and response schemas, adding any resource-specific fields required by the endpoint.

File flows

The Files API is built around a small set of shared objects that work together across upload and download workflows.

Upload flow

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

Download flow

  1. The client requests a file object for a file resource.
  2. The API returns a file object describing the file metadata and temporary presigned URL.
  3. The client downloads the file from the file object's URL.

The Upload object

An Upload object manages the upload and validation workflow used to create a file object. The object tracks the state of the upload job, provides the result metadata for the workflow, and includes a nested file object that describes the file being created and provides the temporary presigned URL the client uses to upload the file bytes with an HTTP PUT request.

Attributes

NameTypeDescription
idstringUnique identifier for the upload job.
statusenumCurrent status of the upload job.
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.
result_urlstringTemporary presigned URL used to download the JSON result file 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 JSON file returned by result_url, hex-encoded. null when result_url is null.
filefile objectFile object for the file being created by the upload job. This object includes the file metadata and the temporary presigned URL the client uses to upload the file bytes with an HTTP PUT request.

Status values

The upload.status field indicates the current state of the upload and validation workflow.

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

Create an Upload

http
POST /{workflow}

Accepts a file object that specifies the metadata for the file being uploaded.

Body parameters

NameTypeRequiredDescription
filefile objectYesFile object containing the metadata for the file being uploaded.

File parameters

Only these fields can be set on the request file object.

NameTypeRequiredDescription
formatenumNoFile format. If omitted, defaults to csv.
schema_versionstringYesSchema version used to validate and interpret the uploaded file.
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 file is for validation only and must not be processed. If omitted, defaults to false.

Response fields

NameTypeDescription
uploadupload objectUpload object for the upload workflow.

Example request

json
{
  "file": {
    "format": "csv",
    "schema_version": "1.0",
    "compression": "gzip",
    "size": 2096128,
    "sha256": "d26b94ae60e4554c7333034960d2146f3801f42a7516a566a014a2f1e6d9c3b7",
    "validate_only": false
  }
}

Example response

json
{
  "upload": {
    "id": "job_9aK2mQ7xT4vN8pR3cW6yZ1bD",
    "status": "ready",
    "created": 1760000000,
    "updated": null,
    "completed": null,
    "result_url": null,
    "result_url_expires": null,
    "result_sha256": null,
    "file": {
      "id": "file_f7Lp2Vx9qM4nT8rC3wK6yH1d",
      "created": 1760000000,
      "format": "csv",
      "schema_version": "1.0",
      "compression": "gzip",
      "size": 2096128,
      "sha256": "d26b94ae60e4554c7333034960d2146f3801f42a7516a566a014a2f1e6d9c3b7",
      "url": "https://files.rslcollective.org/file_f7Lp2Vx9qM4nT8rC3wK6yH1d",
      "url_expires": 1760086400,
      "validate_only": false
    }
  }
}

Result file

An upload result file describes the outcome of a file upload and validation workflow. It is returned via upload.result_url when the upload job reaches a terminal state, succeeded or failed.

The result file is JSON, uses Content-Type: application/json, and contains a top-level result object that describes the outcome of the upload 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.

Attributes

NameTypeDescription
idstringUnique identifier for the job 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. Omitted when no row-level errors were identified.

File-level error 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 error codes

When present, the 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": {
    "id": "job_9aK2mQ7xT4vN8pR3cW6yZ1bD",
    "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": {
    "id": "job_9aK2mQ7xT4vN8pR3cW6yZ1bD",
    "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 CSV file and includes its metadata and transfer information. File objects are used to upload, manage, and download CSV files through RSL Platform APIs.

Files must use UTF-8 encoded CSV with a header row, following RFC 4180.

Attributes

NameTypeDescription
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.
urlstringTemporary presigned URL used to transfer the file. null when no URL is currently available.
url_expirestimestampUTC Unix timestamp when the URL expires. null when url is null.
validate_onlybooleanIf true, the file is for validation only and must not be processed.

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.

Retrieve a file

http
GET /{workflow}/{id}

Returns a file object for the requested file.

Path parameters

NameTypeRequiredDescription
idstringYesIdentifier of the file to retrieve.

Response fields

NameTypeDescription
filefile objectFile object for the requested file.

Example response

json
{
  "file": {
    "id": "file_f7Lp2Vx9qM4nT8rC3wK6yH1d",
    "created": 1774224000,
    "format": "csv",
    "schema_version": "1.0",
    "compression": "gzip",
    "size": 1048576,
    "sha256": "d26b94ae60e4554c7333034960d2146f3801f42a7516a566a014a2f1e6d9c3b7",
    "url": "https://files.rslcollective.org/file_f7Lp2Vx9qM4nT8rC3wK6yH1d.csv.gz",
    "url_expires": 1760086400,
    "validate_only": false
  }
}

File transfers

Interrupted transfers

If a file upload or download is interrupted, the client should retry the same URL while the URL remains valid. When a file is being downloaded, temporary file 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 uploads

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 upload.file.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.

Clients upload file bytes to upload URLs with PUT and retrieve file or result URLs with GET. Upload requests and file download responses use Content-Type: text/csv, even when the file is gzip-compressed.

Temporary upload and download URLs remain valid for at least the minimum interval defined by the applicable API specification.

File 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
  • upload.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 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:
    FileInput:
      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

    Upload:
      type: object
      required:
        - id
        - status
        - created
        - updated
        - completed
        - result_url
        - result_url_expires
        - result_sha256
        - file
      properties:
        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
        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:
          $ref: "#/components/schemas/File"

    UploadResponse:
      type: object
      required: [upload]
      properties:
        upload:
          $ref: "#/components/schemas/Upload"

    File:
      type: object
      required:
        - id
        - created
        - format
        - schema_version
        - compression
        - size
        - sha256
        - url
        - url_expires
        - validate_only
      properties:
        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}$"
        url:
          type: string
          format: uri
          nullable: true
        url_expires:
          type: integer
          nullable: true
        validate_only:
          type: boolean 
          default: false

    FileResponse:
      type: object
      required: [file]
      properties:
        file:
          $ref: "#/components/schemas/File"

    Result:
      oneOf:
        - $ref: "#/components/schemas/ResultSuccess"
        - $ref: "#/components/schemas/ResultFailure"

    ResultResponse:
      type: object
      required: [result]
      properties:
        result:
          $ref: "#/components/schemas/Result"

    ResultSuccess:
      type: object
      required: [id, status, rows_processed, rows_skipped]
      properties:
        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: [id, status, error_code, rows_processed, rows_skipped]
      properties:
        id:
          type: string
        status:
          type: string
          enum: [failed]
        error_code:
          type: string
          enum:
            - validation_failed
            - upload_incomplete
            - 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
          description: >
            Machine-readable row-level error code. Values include shared row error codes
            and workflow-specific row error codes defined by the applicable API.
        error_description:
          type: string

    Error:
      type: object
      required: [error, error_description]
      properties:
        error:
          type: string
        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: 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 file is not valid RFC 4180 CSV.

  - code: invalid_encoding
    category: file
    retryable: false
    description: The uploaded file is not valid UTF-8.

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

api_errors:
  - code: upload_job_in_progress
    category: api
    description: A non-terminal upload job is already in progress for the workflow.

Changelog

  • 2026-03-30: Initial draft.