Multipart HTTP uploads carry files in named form fields. curl sends a local file as multipart/form-data using the file-field name required by the HTTP endpoint. For uploads from PHP code, use PHP cURL multipart form data.
In cURL, each --form option becomes one multipart section. Prefix the local path with @ to send that part as a file upload, keep the field name before the equals sign aligned with the API contract, and append ;type=... when the server validates the part MIME type.
Most failures come from using the wrong field name, sending a raw request body to an endpoint that expects multipart form data, or treating a text field as a file part. Use --form only for browser-style file uploads; raw-body APIs belong to --data-binary, while remote transfer targets such as FTP, SFTP, or PUT uploads use different cURL modes.
Steps to upload a file with curl multipart form data:
- Send a local file as one multipart form field.
$ curl --form "file=@release-manifest.txt" https://httpbin.org/post { "args": {}, ##### snipped ##### "url": "https://httpbin.org/post", "data": "", "files": { "file": "Quarterly release manifest\n" }, "form": {}, ##### snipped ##### }The httpbin.org test service is public and echoes the upload back, so a private file belongs only on your own endpoint. Replace release-manifest.txt with the real local path and https://httpbin.org/post with the real upload URL when the upload is not a test.
The field name is the text before the equals sign. Append ;filename=release-manifest.txt;type=text/plain when the endpoint validates the uploaded filename or MIME type.
Use a different upload mode only when the server expects a raw request body or a remote transfer target instead of a browser-style form.
Related: Send a file as one raw request body
Related: Upload files to FTP or SFTP with cURL - Add text fields in the same request when the API expects metadata beside the uploaded file.
$ curl --form "file=@release-manifest.txt" --form "description=Quarterly release manifest" https://httpbin.org/post { "args": {}, ##### snipped ##### "url": "https://httpbin.org/post", "data": "", "files": { "file": "Quarterly release manifest\n" }, "form": { "description": "Quarterly release manifest" }, ##### snipped ##### }Use --form-string instead of --form when a literal text value might begin with @ or < or include ;type=.
A successful multipart upload should show a response body that names the expected file field.