Sales order attachments — External V1 API

The External V1 API exposes four endpoints for managing files attached to a sales order. These follow the same snake_case conventions as the rest of the External V1 surface and use the same RBAC permissions as the in-app Attachments tab.

Feature flag: All four endpoints return 404 while the sales order attachments feature is not yet enabled for your tenant. Contact your Luminous account team to enable it.


Authentication and permissions

All requests must use a valid External API bearer token. The token's associated user must hold:

  • salesOrders.read — to list or download attachments.
  • salesOrders.update — to upload or delete attachments.

Endpoints

List attachments

GET /external/api/v1/sales-orders/{salesOrderId}/attachments

Returns an array of attachment objects for the order, newest first.

Response body (array of objects):

[
  {
    "id": 42,
    "original_filename": "customer-po.pdf",
    "mime_type": "application/pdf",
    "size_bytes": 204800,
    "uploaded_by": {
      "id": 7,
      "name": "Jane Smith"
    },
    "created_at": "2026-08-15T09:30:00+00:00"
  }
]

No download URL is included in the list response. Fetch the file bytes through the /download endpoint below — it streams over the authenticated connection and never expires.


Upload an attachment

POST /external/api/v1/sales-orders/{salesOrderId}/attachments

Content-Type: multipart/form-data

FieldTypeRequiredNotes
fileBinary fileYesMust be an allowed type; maximum 20 MB

Allowed types: PDF, PNG, JPG/JPEG, GIF, WEBP, DOC, DOCX, XLS, XLSX, CSV, TXT.

Success response (201): The newly created attachment object (same shape as the list item above).

Error responses:

  • 400 — file missing, invalid, over the 20 MB limit, or unsupported type. The error field describes the reason.
  • 404 — sales order not found, or the feature is not enabled.
  • 403 — insufficient permissions.

Upload actions are recorded on the order's activity log.


Download a file

GET /external/api/v1/sales-orders/{salesOrderId}/attachments/{attachmentId}/download

Streams the raw file bytes directly over the authenticated connection. The Content-Type header reflects the stored MIME type; the Content-Disposition header carries the original filename.

Because this is a streamed response (not a redirect to a pre-signed URL), the link never expires and works reliably in automation.


Delete an attachment

DELETE /external/api/v1/sales-orders/{salesOrderId}/attachments/{attachmentId}

Success response (200):

{ "message": "Attachment deleted." }

Deletion removes the stored file permanently and is recorded on the order's activity log.


Error envelope

All error responses follow the standard External V1 shape:

{ "error": "<human-readable message>" }

Typical integration workflow

  1. Read — GET .../attachments after creating or updating a sales order to discover any documents already attached.
  2. Write — POST .../attachments (multipart) to attach a generated PDF (e.g. a confirmation or packing note from your upstream system).
  3. Sync — GET .../attachments/{id}/download to pull a copy into your ERP or document store.
  4. Clean up — DELETE .../attachments/{id} to remove superseded versions before re-uploading.