How to Send Files via Discord Webhook With Multipart Form Data Properly
🔍 WiseChecker

How to Send Files via Discord Webhook With Multipart Form Data Properly

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_json to send the message content, embeds, and username as a JSON string.
  • File field name: Use the field name file to send the binary file data. Each file requires a separate file field.

ADVERTISEMENT

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.

  1. Prepare the JSON payload
    Create a JSON object that contains the message text and optionally an attachments array. For a single file, set the array to [{'id': 0, 'filename': 'example.png'}]. The id must match the index of the file part you will send later. The filename can be any name you want Discord to display.
  2. 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 the Content-Type header of the HTTP request.
  3. Write the request body parts
    Start with the boundary string prefixed by two dashes. Then add the Content-Disposition header 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 the Content-Disposition for the file part: Content-Disposition: form-data; name='file'; filename='example.png'. Include the Content-Type header for the file, such as image/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.
  4. Set the HTTP headers
    Include Content-Type: multipart/form-data; boundary=YOUR_BOUNDARY in the request headers. Do not set Content-Type: application/json because that would tell Discord to expect a JSON body instead of multipart data.
  5. 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/abc where request.txt contains the full multipart body as described.

ADVERTISEMENT

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.

ADVERTISEMENT