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

# Upload a Receipt

> Upload receipts for expenses and card transactions using presigned URLs

Light uses presigned URLs for file uploads. This two-step process keeps your API key secure and supports direct uploads of any size.

## How It Works

```mermaid theme={null}
sequenceDiagram
    participant App as Your App
    participant Light as Light API
    participant S3 as Storage

    App->>Light: POST /upload-url
    Light->>App: { uploadUrl: "https://..." }
    App->>S3: PUT file to presigned URL
    S3->>App: 200 OK
```

## Upload a Receipt for a Card Transaction

<CodeGroup>
  ```javascript Node.js theme={null}
  const fs = require('fs');

  async function uploadReceipt(transactionId, filePath) {
    const API_KEY = process.env.LIGHT_API_KEY;
    const fileName = filePath.split('/').pop();
    const contentType = fileName.endsWith('.pdf') 
      ? 'application/pdf' 
      : 'image/jpeg';

    // Step 1: Get a presigned upload URL
    const urlRes = await fetch(
      `https://api.light.inc/v1/card-transactions/${transactionId}/receipt-upload-url`,
      {
        method: 'POST',
        headers: {
          'Authorization': `Basic ${API_KEY}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ fileName, contentType }),
      }
    );
    const { uploadUrl } = await urlRes.json();

    // Step 2: Upload the file directly
    const fileBuffer = fs.readFileSync(filePath);
    const uploadRes = await fetch(uploadUrl, {
      method: 'PUT',
      headers: { 'Content-Type': contentType },
      body: fileBuffer,
    });

    if (!uploadRes.ok) {
      throw new Error(`Upload failed: ${uploadRes.status}`);
    }

    console.log('Receipt uploaded successfully');
  }

  uploadReceipt('txn_abc123', './receipts/coffee.jpg');
  ```

  ```python Python theme={null}
  import requests
  import os
  import mimetypes

  def upload_receipt(transaction_id: str, file_path: str):
      api_key = os.environ['LIGHT_API_KEY']
      file_name = os.path.basename(file_path)
      content_type = mimetypes.guess_type(file_path)[0] or 'application/octet-stream'

      # Step 1: Get a presigned upload URL
      url_res = requests.post(
          f'https://api.light.inc/v1/card-transactions/{transaction_id}/receipt-upload-url',
          headers={
              'Authorization': f'Basic {api_key}',
              'Content-Type': 'application/json',
          },
          json={'fileName': file_name, 'contentType': content_type},
      )
      upload_url = url_res.json()['uploadUrl']

      # Step 2: Upload the file directly
      with open(file_path, 'rb') as f:
          upload_res = requests.put(
              upload_url,
              headers={'Content-Type': content_type},
              data=f.read(),
          )
      upload_res.raise_for_status()
      print('Receipt uploaded successfully')

  upload_receipt('txn_abc123', './receipts/coffee.jpg')
  ```
</CodeGroup>

## Supported File Types

| Type | Content Type      | Max Size |
| ---- | ----------------- | -------- |
| PDF  | `application/pdf` | 10 MB    |
| JPEG | `image/jpeg`      | 10 MB    |
| PNG  | `image/png`       | 10 MB    |

<Tip>
  Presigned URLs expire after a short period. Always upload the file immediately after obtaining the URL. If the URL expires, request a new one.
</Tip>
