When you send a message to a Discord webhook, you can attach files directly instead of just posting text or URLs. Many developers try to use simple JSON payloads and then wonder why their file attachments fail or appear as broken links. The correct approach requires using multipart/form-data encoding, which lets you include both the file binary data and the JSON payload in one HTTP request. This article explains exactly how to structure that multipart request, what fields are required, and how to avoid the common pitfalls that cause Discord to reject the upload.
Key Takeaways: Discord Webhook File Uploads via Multipart Form Data
- Multipart/form-data boundary: The request must include a unique boundary string that separates the JSON payload from the file data.
- Payload JSON field name: Use the field name
payload_jsonto send the message content, embeds, and username as a JSON string. - File field name: Use the field name
fileto send the binary file data. Each file requires a separatefilefield.
What Is Multipart Form Data and Why Discord Requires It
Discord webhooks accept two types of requests: a simple JSON POST and a multipart/form-data POST. The JSON method works only for text-based messages, embeds, and usernames. When you want to attach a file such as an image, PDF, or ZIP archive, you must switch to multipart/form-data. This encoding allows the HTTP request to contain multiple parts, each with its own content type and headers. One part holds the JSON payload that defines the message, and other parts hold the actual file binary data. Discord reads the payload_json field to get the message metadata and then associates any file fields with that message. Without multipart encoding, the file data would be interpreted as part of the JSON body, which would break the request and return a 400 Bad Request error.
How Discord Processes the Multipart Request
When Discord receives a multipart request, it parses each part sequentially. The payload_json part must appear first. Inside that JSON, you can set properties like content, embeds, username, and avatar_url. You can also include an attachments array that lists metadata for each file you are sending. Each entry in the attachments array must have an id field that matches the part index of the corresponding file field, starting from 0. The filename field in the attachment metadata tells Discord what name to display for the uploaded file. If you omit the attachments array, Discord will still attach the file but will use the original filename from the Content-Disposition header of the file part.
Steps to Send a File via Discord Webhook Using Multipart Form Data
The following steps assume you have a webhook URL from a Discord channel. You can get one by going to Server Settings > Integrations > Webhooks and creating a new webhook. The steps show how to send a single image file with a text message using a standard HTTP client such as cURL or a programming language library.
- Prepare the JSON payload
Create a JSON object that contains the message text and optionally anattachmentsarray. For a single file, set the array to[{'id': 0, 'filename': 'example.png'}]. Theidmust match the index of thefilepart you will send later. Thefilenamecan be any name you want Discord to display. - Set the multipart boundary
Choose a unique string that will not appear in the file data. A common approach is to use a random UUID or a timestamp. For example,----WebKitFormBoundary7MA4YWxkTrZu0gW. This boundary must be placed in theContent-Typeheader of the HTTP request. - Write the request body parts
Start with the boundary string prefixed by two dashes. Then add theContent-Dispositionheader for the JSON part:Content-Disposition: form-data; name='payload_json'. Follow it with a blank line and then the JSON string. After that, add the boundary again, and then theContent-Dispositionfor the file part:Content-Disposition: form-data; name='file'; filename='example.png'. Include theContent-Typeheader for the file, such asimage/png. Add a blank line and then the raw binary data of the file. End the body with the boundary string prefixed by two dashes and suffixed by two dashes. - Set the HTTP headers
IncludeContent-Type: multipart/form-data; boundary=YOUR_BOUNDARYin the request headers. Do not setContent-Type: application/jsonbecause that would tell Discord to expect a JSON body instead of multipart data. - Send the POST request
Use the POST method to send the request to your webhook URL. If you are using cURL, the command looks like:curl -X POST -H 'Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' --data-binary @request.txt https://discord.com/api/webhooks/123456/abcwhererequest.txtcontains the full multipart body as described.
Common Mistakes and How to Avoid Them
Even with the correct multipart structure, several issues can cause the webhook to fail. Below are the most frequent problems and their solutions.
File Shows as an Empty Attachment or Broken Link
This usually happens when the attachments array in the JSON payload is missing or has incorrect id values. Discord uses the id to match the file part to the attachment metadata. If the id is 0 but you sent the file part as the third part instead of the second, Discord cannot link them. Always send the JSON part first, then the file parts in order, and set id to 0 for the first file, 1 for the second, and so on. Also ensure the filename in the JSON matches the filename in the Content-Disposition header of the file part.
Discord Returns 400 Bad Request with ‘Unsupported Media Type’
This error means the Content-Type header is wrong or missing the boundary parameter. Verify that your boundary string is exactly the same in the header and in the body. Also check that the boundary in the body is prefixed with two dashes (--) and that the closing boundary has two dashes at the end. Some HTTP clients automatically add extra headers that override your Content-Type. In that case, set the header explicitly and disable any automatic encoding.
File Size Exceeds Discord’s Limit
Discord webhooks have a file size limit that depends on the server’s Boost level. For a free server, the limit is 8 MB per file. For Boosted servers, it can be up to 50 MB. If your file is larger, you must either compress it or split it into multiple parts. Discord will return a 413 Payload Too Large error if the file exceeds the limit. Check the server’s current upload limit before sending.
Multiple Files Are Sent but Only One Appears
When sending multiple files, each file must have its own file field with a unique name attribute in the Content-Disposition header. You can use file for all of them, but the attachments array must list each file with a distinct id. The order of the file parts in the body must match the order of the id values. If you send file parts out of order, Discord will map them incorrectly.
Discord Webhook File Upload Methods: Multipart vs JSON-Only
| Item | Multipart Form Data | JSON-Only |
|---|---|---|
| File attachment support | Yes, any file type up to size limit | No, only URL-based embeds of images |
| Message content | Supported via payload_json field |
Supported via JSON body |
| Embed support | Supported inside payload_json |
Supported directly in JSON |
| Username customization | Supported inside payload_json |
Supported directly in JSON |
| HTTP method | POST only | POST only |
| Required header | Content-Type: multipart/form-data; boundary=... |
Content-Type: application/json |
You can now send files to any Discord webhook using the correct multipart form data structure. Start by building a small test script with cURL or your preferred programming language to verify the JSON payload and file parts are in the right order. Remember that the payload_json field must always come first, followed by each file in sequence. If you need to send multiple files, increment the id values in the attachments array and keep the file parts in the same order. For advanced use cases, explore the allowed_mentions and flags properties inside the JSON payload to control how Discord handles the message.