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

# Upload File to Order

> End-to-end guide: upload a file, attach it to an order, and notify the customer.

<Note>
  **Beta.** The order asset management and notification endpoints are in active
  development. The request and response shapes shown here are stable for
  production use, but we may add new fields or capabilities without notice.
  [Contact support](mailto:support@filemonk.io) to be notified of breaking changes.
</Note>

## Overview

A common workflow for custom/made-to-order products is:

1. **Upload** a file via the [Upload Asset](/api-reference/assets/upload-asset) flow
2. **Attach** it to a specific order
3. **Notify** the customer so they receive the download email

This guide walks through all three steps.

## 1. Upload the file

Create an internal asset and upload the file body. See
[Upload Asset](/api-reference/assets/upload-asset) for the full reference.

<CodeGroup>
  ```bash cURL theme={null}
  # Step 1a: Create the asset and get the presigned upload URL
  RESPONSE=$(curl -s -X POST 'https://app.filemonk.io/api/v1/external/assets' \
    -H 'X-Auth-Token: fm_api_key_your_key_here' \
    -H 'Content-Type: application/json' \
    -d '{
      "asset": {
        "type": "internal",
        "filename": "custom-song.mp3",
        "byte_size": 5242880,
        "content_type": "audio/mpeg"
      }
    }')

  ASSET_ID=$(echo $RESPONSE | jq -r '.asset.id')
  UPLOAD_URL=$(echo $RESPONSE | jq -r '.upload.url')

  # Step 1b: Upload the file body
  curl -X PUT "$UPLOAD_URL" \
    -H "Content-Type: audio/mpeg" \
    -H "Content-Disposition: inline; filename=\"custom-song.mp3\"" \
    --upload-file ./custom-song.mp3
  ```

  ```javascript Node.js theme={null}
  import { readFile, stat } from 'node:fs/promises';

  const API_KEY = 'fm_api_key_your_key_here';
  const BASE = 'https://app.filemonk.io/api/v1/external';

  // Step 1a: Create the asset
  const filePath = './custom-song.mp3';
  const stats = await stat(filePath);

  const create = await fetch(`${BASE}/assets`, {
    method: 'POST',
    headers: {
      'X-Auth-Token': API_KEY,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      asset: {
        type: 'internal',
        filename: 'custom-song.mp3',
        byte_size: stats.size,
        content_type: 'audio/mpeg'
      }
    })
  }).then(r => r.json());

  // Step 1b: Upload the file body
  const body = await readFile(filePath);
  await fetch(create.upload.url, {
    method: 'PUT',
    headers: create.upload.headers,
    body
  });

  const assetId = create.asset.id;
  ```

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

  API_KEY = 'fm_api_key_your_key_here'
  BASE = 'https://app.filemonk.io/api/v1/external'

  # Step 1a: Create the asset
  file_path = './custom-song.mp3'
  byte_size = os.path.getsize(file_path)

  create = requests.post(
      f'{BASE}/assets',
      headers={'X-Auth-Token': API_KEY},
      json={
          'asset': {
              'type': 'internal',
              'filename': 'custom-song.mp3',
              'byte_size': byte_size,
              'content_type': 'audio/mpeg'
          }
      }
  ).json()

  # Step 1b: Upload the file body
  with open(file_path, 'rb') as f:
      requests.put(create['upload']['url'], headers=create['upload']['headers'], data=f).raise_for_status()

  asset_id = create['asset']['id']
  ```
</CodeGroup>

## 2. Attach the asset to the order

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://app.filemonk.io/api/v1/external/orders/$ORDER_ID/attach_assets" \
    -H 'X-Auth-Token: fm_api_key_your_key_here' \
    -H 'Content-Type: application/json' \
    -d "{\"asset_ids\": [\"$ASSET_ID\"]}"
  ```

  ```javascript Node.js theme={null}
  const orderId = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890';

  await fetch(`${BASE}/orders/${orderId}/attach_assets`, {
    method: 'POST',
    headers: {
      'X-Auth-Token': API_KEY,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ asset_ids: [assetId] })
  });
  ```

  ```python Python theme={null}
  order_id = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'

  requests.post(
      f'{BASE}/orders/{order_id}/attach_assets',
      headers={'X-Auth-Token': API_KEY},
      json={'asset_ids': [asset_id]}
  ).raise_for_status()
  ```
</CodeGroup>

## 3. Notify the customer

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://app.filemonk.io/api/v1/external/orders/$ORDER_ID/notify" \
    -H 'X-Auth-Token: fm_api_key_your_key_here' \
    -H 'Content-Type: application/json'
  ```

  ```javascript Node.js theme={null}
  const notify = await fetch(`${BASE}/orders/${orderId}/notify`, {
    method: 'POST',
    headers: {
      'X-Auth-Token': API_KEY,
      'Content-Type': 'application/json'
    }
  }).then(r => r.json());

  console.log('Notified at:', notify.notified_at);
  ```

  ```python Python theme={null}
  notify = requests.post(
      f'{BASE}/orders/{order_id}/notify',
      headers={'X-Auth-Token': API_KEY}
  ).json()

  print('Notified at:', notify['notified_at'])
  ```
</CodeGroup>

That's it — the customer will receive a download email with a link to their
custom file.

<Tip>
  You can also use an **external URL** asset instead of uploading a file. Create
  the asset with `type: "external"` and `external_url` pointing to your hosted
  file, then follow steps 2 and 3 above.
</Tip>

## Using an external URL instead

If your file is already hosted elsewhere, skip the upload and create an external
asset instead:

```bash cURL theme={null}
curl -X POST 'https://app.filemonk.io/api/v1/external/assets' \
  -H 'X-Auth-Token: fm_api_key_your_key_here' \
  -H 'Content-Type: application/json' \
  -d '{
    "asset": {
      "type": "external",
      "external_url": "https://cdn.example.com/songs/custom-song-1042.mp3",
      "name": "Custom Song"
    }
  }'
```

Then attach and notify as above.
