# Files

## Upload file bytes directly

**post** `/v5/files`

Upload a file's bytes directly and create a file record.

Send the file as multipart/form-data in the `file` field; the request body
carries the raw bytes, unlike cloud_imports which only references blobs that
already exist in cloud storage. The upload is rejected if it exceeds 25 MB;
larger or direct-to-storage uploads use a separate upload flow. The server
detects the content type from the bytes and rejects content that fails the
structural validation for that type. Content is deduplicated by checksum
and MIME type, so uploading bytes identical to an existing file reuses the
already-stored object instead of storing a second copy. Returns the created
file's metadata.

### Header Parameters

- `"x-project-id": optional string`

### Returns

- `SGPFile object { id, created_at, created_by, 7 more }`

  - `id: string`

    The unique identifier of the entity.

  - `created_at: string`

    The date and time when the entity was created in ISO format.

  - `created_by: Identity`

    The identity that created the entity.

    - `id: string`

    - `type: "user" or "service_account"`

      - `"user"`

      - `"service_account"`

    - `object: optional "identity"`

      - `"identity"`

  - `filename: string`

  - `md5_checksum: string`

  - `mime_type: string`

  - `size: number`

  - `duration_seconds: optional number`

  - `object: optional "file"`

    - `"file"`

  - `tags: optional map[unknown]`

### Example

```http
curl https://api.egp.scale.com/v5/files \
    -H 'Content-Type: multipart/form-data' \
    -H "x-api-key: $SGP_API_KEY" \
    -F 'file=@/path/to/file'
```

#### Response

```json
{
  "id": "id",
  "created_at": "2019-12-27T18:11:19.117Z",
  "created_by": {
    "id": "id",
    "type": "user",
    "object": "identity"
  },
  "filename": "filename",
  "md5_checksum": "md5_checksum",
  "mime_type": "mime_type",
  "size": 0,
  "duration_seconds": 0,
  "object": "file",
  "tags": {
    "foo": "bar"
  }
}
```

## Import files from cloud storage

**post** `/v5/files/cloud_imports`

Register files that already exist in cloud blob storage as file records, in one batch.

Unlike upload, this transfers no bytes: each entry references an existing
object by its container/bucket, filepath, filename, and MIME type, and only a
metadata record pointing at that object is created. Files are imported
independently and the response reports a per-file status. The response is 200
when every import succeeds and 207 when results are mixed, with each result
marked SUCCESS or a failure reason (file does not exist, invalid permissions,
or unknown error). Failed entries carry only the submitted filename and MIME
type rather than a full file record.

### Header Parameters

- `"x-project-id": optional string`

### Body Parameters

- `files: array of object { container, file_type, filename, filepath }`

  List of files to import from cloud storage

  - `container: string`

    The cloud storage container/bucket name

  - `file_type: string`

    The MIME type of the file

  - `filename: string`

    The name of the file

  - `filepath: string`

    The path to the file within the container

### Returns

- `results: array of object { file, status }`

  Results for each file import attempt

  - `file: SGPFile or object { filename, mime_type, object }`

    The file object (full File for success, minimal _FailedFile for failures)

    - `SGPFile object { id, created_at, created_by, 7 more }`

      - `id: string`

        The unique identifier of the entity.

      - `created_at: string`

        The date and time when the entity was created in ISO format.

      - `created_by: Identity`

        The identity that created the entity.

        - `id: string`

        - `type: "user" or "service_account"`

          - `"user"`

          - `"service_account"`

        - `object: optional "identity"`

          - `"identity"`

      - `filename: string`

      - `md5_checksum: string`

      - `mime_type: string`

      - `size: number`

      - `duration_seconds: optional number`

      - `object: optional "file"`

        - `"file"`

      - `tags: optional map[unknown]`

    - `_FailedFile object { filename, mime_type, object }`

      Minimal file representation for failed uploads containing only essential information.

      - `filename: string`

        The original filename from the request

      - `mime_type: string`

        The original MIME type from the request

      - `object: optional "failed_file"`

        - `"failed_file"`

  - `status: "SUCCESS" or "FAILED_FILE_DOES_NOT_EXIST" or "FAILED_INVALID_PERMISSIONS" or "FAILED_UNKNOWN_ERROR"`

    The status of the upload attempt

    - `"SUCCESS"`

    - `"FAILED_FILE_DOES_NOT_EXIST"`

    - `"FAILED_INVALID_PERMISSIONS"`

    - `"FAILED_UNKNOWN_ERROR"`

### Example

```http
curl https://api.egp.scale.com/v5/files/cloud_imports \
    -H 'Content-Type: application/json' \
    -H "x-api-key: $SGP_API_KEY" \
    -d '{
          "files": [
            {
              "container": "container",
              "file_type": "file_type",
              "filename": "filename",
              "filepath": "filepath"
            }
          ]
        }'
```

#### Response

```json
{
  "results": [
    {
      "file": {
        "id": "id",
        "created_at": "2019-12-27T18:11:19.117Z",
        "created_by": {
          "id": "id",
          "type": "user",
          "object": "identity"
        },
        "filename": "filename",
        "md5_checksum": "md5_checksum",
        "mime_type": "mime_type",
        "size": 0,
        "duration_seconds": 0,
        "object": "file",
        "tags": {
          "foo": "bar"
        }
      },
      "status": "SUCCESS"
    }
  ]
}
```

## List files

**get** `/v5/files`

List the account's files with pagination.

Optionally filter by `filename` (case-insensitive partial match). Results
are scoped to the files the caller is authorized to read. Files marked hidden
(internal or service-owned artifacts) are excluded from this listing but
remain retrievable by id. Returns file metadata only, not content.

### Query Parameters

- `ending_before: optional string`

- `filename: optional string`

  Filter files by filename (case-insensitive partial match)

- `limit: optional number`

- `sort_by: optional string`

- `sort_order: optional SortOrder`

  - `"asc"`

  - `"desc"`

- `starting_after: optional string`

### Header Parameters

- `"x-project-id": optional string`

### Returns

- `has_more: boolean`

  Whether there are more items left to be fetched.

- `items: array of SGPFile`

  - `id: string`

    The unique identifier of the entity.

  - `created_at: string`

    The date and time when the entity was created in ISO format.

  - `created_by: Identity`

    The identity that created the entity.

    - `id: string`

    - `type: "user" or "service_account"`

      - `"user"`

      - `"service_account"`

    - `object: optional "identity"`

      - `"identity"`

  - `filename: string`

  - `md5_checksum: string`

  - `mime_type: string`

  - `size: number`

  - `duration_seconds: optional number`

  - `object: optional "file"`

    - `"file"`

  - `tags: optional map[unknown]`

- `total: number`

  The total of items that match the query. This is greater than or equal to the number of items returned.

- `limit: optional number`

  The maximum number of items to return.

- `object: optional "list"`

  - `"list"`

### Example

```http
curl https://api.egp.scale.com/v5/files \
    -H "x-api-key: $SGP_API_KEY"
```

#### Response

```json
{
  "has_more": true,
  "items": [
    {
      "id": "id",
      "created_at": "2019-12-27T18:11:19.117Z",
      "created_by": {
        "id": "id",
        "type": "user",
        "object": "identity"
      },
      "filename": "filename",
      "md5_checksum": "md5_checksum",
      "mime_type": "mime_type",
      "size": 0,
      "duration_seconds": 0,
      "object": "file",
      "tags": {
        "foo": "bar"
      }
    }
  ],
  "total": 0,
  "limit": 0,
  "object": "list"
}
```

## Update a file

**patch** `/v5/files/{file_id}`

Update a file's mutable metadata by id.

Only the file's `tags` can be modified; filename, content, size, and other
attributes are immutable through this endpoint. The supplied tags replace the
file's existing tags. Returns the updated file metadata.

### Path Parameters

- `file_id: string`

### Header Parameters

- `"x-project-id": optional string`

### Body Parameters

- `tags: optional map[unknown]`

### Returns

- `SGPFile object { id, created_at, created_by, 7 more }`

  - `id: string`

    The unique identifier of the entity.

  - `created_at: string`

    The date and time when the entity was created in ISO format.

  - `created_by: Identity`

    The identity that created the entity.

    - `id: string`

    - `type: "user" or "service_account"`

      - `"user"`

      - `"service_account"`

    - `object: optional "identity"`

      - `"identity"`

  - `filename: string`

  - `md5_checksum: string`

  - `mime_type: string`

  - `size: number`

  - `duration_seconds: optional number`

  - `object: optional "file"`

    - `"file"`

  - `tags: optional map[unknown]`

### Example

```http
curl https://api.egp.scale.com/v5/files/$FILE_ID \
    -X PATCH \
    -H 'Content-Type: application/json' \
    -H "x-api-key: $SGP_API_KEY" \
    -d '{}'
```

#### Response

```json
{
  "id": "id",
  "created_at": "2019-12-27T18:11:19.117Z",
  "created_by": {
    "id": "id",
    "type": "user",
    "object": "identity"
  },
  "filename": "filename",
  "md5_checksum": "md5_checksum",
  "mime_type": "mime_type",
  "size": 0,
  "duration_seconds": 0,
  "object": "file",
  "tags": {
    "foo": "bar"
  }
}
```

## Get file metadata

**get** `/v5/files/{file_id}`

Retrieve a single file's metadata by id.

Returns the file record (id, filename, MIME type, size, tags, and related
fields) but not the file's bytes; use the content endpoint to download the
bytes.

### Path Parameters

- `file_id: string`

### Header Parameters

- `"x-project-id": optional string`

### Returns

- `SGPFile object { id, created_at, created_by, 7 more }`

  - `id: string`

    The unique identifier of the entity.

  - `created_at: string`

    The date and time when the entity was created in ISO format.

  - `created_by: Identity`

    The identity that created the entity.

    - `id: string`

    - `type: "user" or "service_account"`

      - `"user"`

      - `"service_account"`

    - `object: optional "identity"`

      - `"identity"`

  - `filename: string`

  - `md5_checksum: string`

  - `mime_type: string`

  - `size: number`

  - `duration_seconds: optional number`

  - `object: optional "file"`

    - `"file"`

  - `tags: optional map[unknown]`

### Example

```http
curl https://api.egp.scale.com/v5/files/$FILE_ID \
    -H "x-api-key: $SGP_API_KEY"
```

#### Response

```json
{
  "id": "id",
  "created_at": "2019-12-27T18:11:19.117Z",
  "created_by": {
    "id": "id",
    "type": "user",
    "object": "identity"
  },
  "filename": "filename",
  "md5_checksum": "md5_checksum",
  "mime_type": "mime_type",
  "size": 0,
  "duration_seconds": 0,
  "object": "file",
  "tags": {
    "foo": "bar"
  }
}
```

## Delete a file

**delete** `/v5/files/{file_id}`

Delete a file by id, removing its database record.

This is a hard delete: the file's row is removed from the database, not
soft-archived. The underlying stored object is deleted only when no other
file record still references the same stored content (identical checksum and
MIME type); when another record shares the blob, the blob is retained. If the
id refers to an incomplete multipart upload placeholder, its staged parts are
aborted instead. Returns a confirmation carrying the deleted file's id.

### Path Parameters

- `file_id: string`

### Header Parameters

- `"x-project-id": optional string`

### Returns

- `id: string`

- `deleted: boolean`

- `object: optional "file"`

  - `"file"`

### Example

```http
curl https://api.egp.scale.com/v5/files/$FILE_ID \
    -X DELETE \
    -H "x-api-key: $SGP_API_KEY"
```

#### Response

```json
{
  "id": "id",
  "deleted": true,
  "object": "file"
}
```

## Domain Types

### SGP File

- `SGPFile object { id, created_at, created_by, 7 more }`

  - `id: string`

    The unique identifier of the entity.

  - `created_at: string`

    The date and time when the entity was created in ISO format.

  - `created_by: Identity`

    The identity that created the entity.

    - `id: string`

    - `type: "user" or "service_account"`

      - `"user"`

      - `"service_account"`

    - `object: optional "identity"`

      - `"identity"`

  - `filename: string`

  - `md5_checksum: string`

  - `mime_type: string`

  - `size: number`

  - `duration_seconds: optional number`

  - `object: optional "file"`

    - `"file"`

  - `tags: optional map[unknown]`

### File Import From Cloud Response

- `FileImportFromCloudResponse object { results }`

  - `results: array of object { file, status }`

    Results for each file import attempt

    - `file: SGPFile or object { filename, mime_type, object }`

      The file object (full File for success, minimal _FailedFile for failures)

      - `SGPFile object { id, created_at, created_by, 7 more }`

        - `id: string`

          The unique identifier of the entity.

        - `created_at: string`

          The date and time when the entity was created in ISO format.

        - `created_by: Identity`

          The identity that created the entity.

          - `id: string`

          - `type: "user" or "service_account"`

            - `"user"`

            - `"service_account"`

          - `object: optional "identity"`

            - `"identity"`

        - `filename: string`

        - `md5_checksum: string`

        - `mime_type: string`

        - `size: number`

        - `duration_seconds: optional number`

        - `object: optional "file"`

          - `"file"`

        - `tags: optional map[unknown]`

      - `_FailedFile object { filename, mime_type, object }`

        Minimal file representation for failed uploads containing only essential information.

        - `filename: string`

          The original filename from the request

        - `mime_type: string`

          The original MIME type from the request

        - `object: optional "failed_file"`

          - `"failed_file"`

    - `status: "SUCCESS" or "FAILED_FILE_DOES_NOT_EXIST" or "FAILED_INVALID_PERMISSIONS" or "FAILED_UNKNOWN_ERROR"`

      The status of the upload attempt

      - `"SUCCESS"`

      - `"FAILED_FILE_DOES_NOT_EXIST"`

      - `"FAILED_INVALID_PERMISSIONS"`

      - `"FAILED_UNKNOWN_ERROR"`

### File Delete Response

- `FileDeleteResponse object { id, deleted, object }`

  - `id: string`

  - `deleted: boolean`

  - `object: optional "file"`

    - `"file"`

# Content

## Download file content

**get** `/v5/files/{file_id}/content`

Download the raw bytes of a file by id.

Streams the stored object's content back directly (not a redirect or signed
URL), with the response Content-Type set to the file's stored MIME type and
Content-Disposition set to attachment. Use the metadata endpoint for size,
filename, and other attributes.

### Path Parameters

- `file_id: string`

### Header Parameters

- `"x-project-id": optional string`

### Example

```http
curl https://api.egp.scale.com/v5/files/$FILE_ID/content \
    -H "x-api-key: $SGP_API_KEY"
```

#### Response

```json
{}
```

## Domain Types

### Content Retrieve Response

- `ContentRetrieveResponse = unknown`
