> ## Documentation Index
> Fetch the complete documentation index at: https://docs.trelent.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart: Process uploaded files

> Upload a local file, run it through the Data Ingestion pipeline, and pull the results back.

Use this quickstart to go from a file on your machine to Markdown output in three steps. It relies on the **file connector**, which processes files you upload directly to the Data Ingestion API.

## Prerequisites

* `TRELENT_DATA_INGESTION_API_URL` pointing to your deployment
* `TRELENT_DATA_INGESTION_API_TOKEN` token with the `FILE:UPLOAD` permission
* A PDF, video, or Office document to ingest (for example `sample.pdf`)

<Tabs>
  <Tab title="TypeScript">
    ## Installation

    <CodeGroup>
      ```bash bun theme={null}
      bun add @trelent/data-ingestion
      ```

      ```bash npm theme={null}
      npm install @trelent/data-ingestion
      ```

      ```bash yarn theme={null}
      yarn add @trelent/data-ingestion
      ```

      ```bash pnpm theme={null}
      pnpm add @trelent/data-ingestion
      ```
    </CodeGroup>

    <Steps>
      <Step title="Upload a file">
        Upload a file to the API. It stores the object under your account and returns a file ID that stays valid until the upload expires.

        ```ts theme={null}
        import { DataIngestionClient } from "@trelent/data-ingestion";
        import { readFileSync } from "fs";

        const client = new DataIngestionClient();

        const fileBuffer = readFileSync("sample.pdf");
        const blob = new Blob([fileBuffer], { type: "application/pdf" });

        const upload = await client.uploadFile(blob, "sample.pdf", { expiresInDays: 30 });
        console.log("Uploaded file:", upload.id);
        ```

        <Tip>
          Files expire after 30 days by default. Adjust `expiresInDays` if you need a shorter retention period.
        </Tip>
      </Step>

      <Step title="Start a job with the file connector">
        Use the returned file ID to create a job. The connector definition references one or more uploaded files and tells the service to pull inputs from managed storage.

        ```ts theme={null}
        import { DataIngestionClient } from "@trelent/data-ingestion";
        import type { JobInput } from "@trelent/data-ingestion";

        const client = new DataIngestionClient();

        const job: JobInput = {
          connector: {
            type: "file_upload",
            file_ids: [upload.id],
          },
          output: {
            type: "s3-signed-url",
            expires_minutes: 120,
          },
        };

        const response = await client.submitJob(job);
        console.log("Job submitted:", response.job_id);
        ```

        <Check>
          On success, the API responds with a `job_id`. Capture that ID for status polling.
        </Check>
      </Step>

      <Step title="Poll job status and retrieve outputs">
        Query the job status until it becomes `completed`. When complete, the response includes delivery pointers (signed URLs or bucket locations) for generated Markdown and images.

        ```ts theme={null}
        import { DataIngestionClient } from "@trelent/data-ingestion";

        const client = new DataIngestionClient();

        const status = await client.getJobStatus(response.job_id, {
          includeMarkdown: false,
          includeFileMetadata: true,
        });

        console.log("Status:", status.status);
        if (status.delivery) {
          console.log("Deliveries:", Object.keys(status.delivery));
        }
        ```

        <Info>
          If you need to reuse uploads across multiple jobs, call `listFiles()` to list every file ID still within its retention window.
        </Info>

        <Warning>
          If a file fails to process, check `status.errors` for details. Errors are keyed by the input identifier (file ID).
        </Warning>
      </Step>
    </Steps>
  </Tab>

  <Tab title="Python">
    ## Installation

    <CodeGroup>
      ```bash pip theme={null}
      pip install trelent-data-ingestion
      ```

      ```bash uv theme={null}
      uv add trelent-data-ingestion
      ```
    </CodeGroup>

    <Steps>
      <Step title="Upload a file">
        Upload a file to the API. It stores the object under your account and returns a file ID that stays valid until the upload expires.

        ```python theme={null}
        from pathlib import Path
        from trelent_data_ingestion_sdk import DataIngestionClient

        client = DataIngestionClient()

        file_data = Path("sample.pdf").read_bytes()
        upload = client.upload_file(file_data, "sample.pdf", content_type="application/pdf", expires_in_days=30)
        print("Uploaded file:", upload.id)
        ```

        <Tip>
          Files expire after 30 days by default. Adjust `expires_in_days` if you need a shorter retention period.
        </Tip>
      </Step>

      <Step title="Start a job with the file connector">
        Use the returned file ID to create a job. The connector definition references one or more uploaded files and tells the service to pull inputs from managed storage.

        ```python theme={null}
        from trelent_data_ingestion_sdk import DataIngestionClient, JobInput, FileUploadConnector, S3SignedUrlOutput

        client = DataIngestionClient()

        job = JobInput(
            connector=FileUploadConnector(file_ids=[upload.id]),
            output=S3SignedUrlOutput(expires_minutes=120),
        )

        response = client.submit_job(job)
        print("Job submitted:", response.job_id)
        ```

        <Check>
          On success, the API responds with a `job_id`. Capture that ID for status polling.
        </Check>
      </Step>

      <Step title="Poll job status and retrieve outputs">
        Query the job status until it becomes `completed`. When complete, the response includes delivery pointers (signed URLs or bucket locations) for generated Markdown and images.

        ```python theme={null}
        from trelent_data_ingestion_sdk import DataIngestionClient

        client = DataIngestionClient()

        status = client.get_job_status(
            response.job_id,
            include_markdown=False,
            include_file_metadata=True,
        )

        print("Status:", status.status)
        if status.delivery:
            print("Deliveries:", list(status.delivery.keys()))
        ```

        <Info>
          If you need to reuse uploads across multiple jobs, call `list_files()` to list every file ID still within its retention window.
        </Info>

        <Warning>
          If a file fails to process, check `status.errors` for details. Errors are keyed by the input identifier (file ID).
        </Warning>
      </Step>
    </Steps>
  </Tab>
</Tabs>
