Send and download attachments
In the desktop or web client, use the attachment button, paste a file or image, or drop files into the message box. Review or remove the staged files, then select Send to send your text and each file as separate messages. JPEG, PNG, GIF and WebP files become images; MOV, MP4, 3GP, 3G2 and MJ2 files become videos; other formats become file attachments. The client checks the connected hub’s limits; the synthetic preview has a smaller file limit than a native hub.
Send attachments through the CLI, HTTP API or OpenClaw. The ordinary-file source limit is 512 MiB (536,870,912 bytes). Limits depend on the selected send kind:
| Send kind | Maximum source size |
|---|---|
| Ordinary file | 536,870,912 bytes |
| Video source | 52,428,800 bytes (50 MiB) |
| Image or voice | 26,214,383 bytes each (25 MiB minus 17 bytes) |
| Sticker | Sending unavailable |
File attachments preserve source bytes. Image sends can resize/re-encode them. See Video and image quality for outgoing preparation and how to request received copies.
CLI
-
Send a file and allow an hour for upload, download verification and submission:
Terminal window wx messages send filehelper --file ./report.pdf --wait 3600 \--idempotency-key report-2026-10--waitis in seconds; its default is 30 and attachment jobs allow up to 3,600.--detachreturns the job immediately. -
If the wait ends, inspect the returned job:
Terminal window wx jobs get JOB_IDWhile the daemon verifies the uploaded bytes, the job shows these fields:
Phase: readbackState: runningKeep the job ID and key. Ending the wait leaves the daemon working.
HTTP API and SDK
-
Inspect the connected daemon’s limits with
GET /v1/accounts/{account}/capabilities. The relevant response fields are:{"mediaUploadMaxBytes": 536870912,"mediaSendMaxBytes": {"file": 536870912,"image": 26214383,"video": 52428800,"voice": 26214383}}mediaUploadMaxByteslimits staging. CheckmediaSendMaxBytes[kind]before staging bytes for a particular send. -
Stage one file, then submit its returned
idassourceId:Terminal window curl -H "Authorization: Bearer $TOKEN" -F 'file=@report.pdf' \"$WX/accounts/$ACCOUNT/uploads"curl -X POST -H "Authorization: Bearer $TOKEN" \-H 'Content-Type: application/json' -H 'Idempotency-Key: report-2026-10' \-d '{"threadId":"filehelper","kind":"file","sourceId":"SOURCE_ID"}' \"$WX/accounts/$ACCOUNT/sends"Here,
WXends in/v1. The send returns HTTP 202 with a job. PollGET /jobs/{id}; allow up to an hour for larger files.The TypeScript SDK exposes the same workflow:
const source = await client.upload(accountId, bytes, "report.pdf");const job = await client.sendMedia(accountId, {threadId: "filehelper", kind: "file", sourceId: source.id,standardSourceId: null, thumbnailSourceId: null,playSeconds: null, durationMs: null,}, "report-2026-10");const progress = await client.job(accountId, job.id);SDK uploads accept bytes or a
Blob; Node’sopenAsBlobavoids loading the source into memory.NATIVE_MAX_SOURCE_BYTES, exported by@agent-wechat/shared, is the staging ceiling.
Download files
Ordinary-file downloads also support up to 512 MiB:
wx messages media filehelper MESSAGE_ID --output ./saved.pdf --wait 3600The CLI verifies size and SHA-256 before publishing the output. SDK clients can use mediaContentStream with { maxBytes: NATIVE_MAX_SOURCE_BYTES }; the default retrieval bound is 128 MiB. Check the selected asset’s size and SHA-256 when saving the stream.
OpenClaw
Set channels.agent-wechat.mediaMaxMb to allow the intended attachment size. For example, 512 permits files up to 512 MiB. The extension applies the smaller of this setting and the selected send kind’s limit before staging. Raising it cannot extend the daemon’s per-kind limits.
Ordinary audio is sent as a file; audioAsVoice selects voice. Larger ordinary files get up to an hour of job polling. If polling ends, retain the reported job ID and inspect it instead of starting another send.
Use OpenClaw’s asDocument/forceDocument option to send media as an ordinary file. Video quality options apply only to video sends.