Insert a file attachment
Uploads a file and attaches it to exactly one existing record. On success the file is stored and
served back through the url on the response, so a single call both persists the document and
makes it downloadable.
Send the request as multipart/form-data with three parts:
• file — the binary to upload. Required, and must be non-empty (a zero-byte file is rejected).
• name — optional display name; defaults to the uploaded file's original filename when omitted or blank.
• exactly one reference id (product_id, order_id, purchase_id, ...) naming the record to attach to. Supply the id — the same id that record's own endpoint returns. Providing no reference id is rejected, and providing more than one is also rejected; exactly one is required.
This endpoint is create-only. There is no public endpoint to update or delete an attachment, and a file cannot be replaced once uploaded — upload a new attachment instead. The response echoes the attachment with all reference-id fields present but only the one you set populated; the rest are null.
The attachment is owned by the company tied to the API key you authenticate with, and the response's
uploader is the user that key belongs to. On success you get a 201 with the created attachment
wrapped in a data envelope; its url is immediately downloadable.
System effects: the upload counts against your company's storage quota. If it would exceed the remaining quota the call fails with 400 and nothing is stored — free space under Settings (or remove other attachments) and retry. This endpoint does not move inventory and does not push to Metrc or BioTrack; it only associates a document with the referenced record.
Required permission: products_permissions_edit.
BearerAuthorizationBearer <token>API token generated in Distru (Settings → Distru API). Send it on every request as Authorization: Bearer YOUR_API_TOKEN.
multipart/form-data- body
file*unknownThe binary file to upload, sent as a multipart part. Required and must be non-empty — a zero-byte file is rejected. When name is omitted or blank, the uploaded file's original filename becomes the attachment name.
name?stringDisplay name for the attachment. Defaults to the uploaded file's original filename when omitted or blank. Max 255 characters.
product_id?stringID of the product to attach this file to, as returned by the product endpoints. Exactly one reference id must be provided across all *_id fields on this request — providing none, or more than one, is rejected.
order_id?stringID of the order to attach this file to, as returned by the order endpoints. Exactly one reference id must be provided across all *_id fields on this request — providing none, or more than one, is rejected.
purchase_id?stringID of the purchase to attach this file to, as returned by the purchase endpoints. Exactly one reference id must be provided across all *_id fields on this request — providing none, or more than one, is rejected.
invoice_id?stringID of the invoice to attach this file to, as returned by the invoice endpoints. Exactly one reference id must be provided across all *_id fields on this request — providing none, or more than one, is rejected.
batch_id?stringID of the batch to attach this file to, as returned by the batch endpoints. Exactly one reference id must be provided across all *_id fields on this request — providing none, or more than one, is rejected.
contact_id?stringID of the contact to attach this file to, as returned by the contact endpoints. Exactly one reference id must be provided across all *_id fields on this request — providing none, or more than one, is rejected.
company_id?stringID of the company to attach this file to, as returned by the company endpoints. Exactly one reference id must be provided across all *_id fields on this request — providing none, or more than one, is rejected.
request_id?stringID of the request to attach this file to. Exactly one reference id must be provided across all *_id fields on this request — providing none, or more than one, is rejected.
task_id?stringID of the task to attach this file to. Exactly one reference id must be provided across all *_id fields on this request — providing none, or more than one, is rejected.
stock_transfer_id?stringID of the stock transfer to attach this file to. Exactly one reference id must be provided across all *_id fields on this request — providing none, or more than one, is rejected.
assembly_id?stringID of the assembly to attach this file to, as returned by the assembly endpoints. Exactly one reference id must be provided across all *_id fields on this request — providing none, or more than one, is rejected.
return_id?stringID of the return to attach this file to. Exactly one reference id must be provided across all *_id fields on this request — providing none, or more than one, is rejected.
order_shipment_id?stringID of the order shipment to attach this file to. Exactly one reference id must be provided across all *_id fields on this request — providing none, or more than one, is rejected.
license_id?stringID of the license to attach this file to. Exactly one reference id must be provided across all *_id fields on this request — providing none, or more than one, is rejected.
File attachment inserted successfully
*/*- response
A single file attachment wrapped in a data envelope
data?A file attachment
curl -X POST 'https://app.distru.com/public/v1/file-attachments' \ -F 'file=null'{ "data": { "assembly_id": null, "batch_id": null, "company_id": null, "company_relationship_id": null, "contact_id": null, "id": "00000000-0000-0000-0000-000000000481", "invoice_id": null, "license_id": null, "mime_type": "image/png", "name": "My Test Image", "order_id": null, "order_shipment_id": null, "product_id": "ebeb6641-7391-4213-9244-edcdebba84b6", "purchase_id": null, "request_id": null, "return_id": null, "size_in_bytes": 355974, "stock_transfer_id": null, "task_id": null, "upload_datetime": "2026-11-06T08:18:34.931343Z", "uploader": { "id": "00000000-0000-0000-0000-00000005a31c", "name": "FirstName4372 LastName4373" }, "url": "https://example.com/your-file" }}