Skip to main content

Media Upload

The client.media API handles file uploads and exposes the server's async processing state without adding a client-side waiting deadline.

Uploading media​

import 'dart:io';

final bytes = await File('photo.jpg').readAsBytes();
final attachment = await client.media.upload(
bytes,
'photo.jpg',
description: 'Alt text for accessibility',
);

print(attachment.id);
print(attachment.url);

Upload with thumbnail​

final thumbnailBytes = await File('thumb.jpg').readAsBytes();

final attachment = await client.media.upload(
videoBytes,
'video.mp4',
description: 'A short clip',
thumbnail: thumbnailBytes,
thumbnailFilename: 'thumb.jpg',
);

Focal point​

The focal point determines which part of the image remains visible when cropped. Values range from -1.0 to 1.0 for both axes:

final attachment = await client.media.upload(
bytes,
'photo.jpg',
focus: '0.0,-0.5', // Center horizontally, upper half
);

Async processing​

When the server returns HTTP 202, upload() returns the attachment immediately with a null url. Call fetchById() when your application needs to check the status. HTTP 206 means processing is still in progress, while HTTP 200 means the latest attachment state is available. The library does not poll or impose a processing deadline.

If Mastodon reports HTTP 422, fetchById() surfaces the processing failure as MastodonValidationException through the standard error conversion path.

final attachment = await client.media.upload(bytes, 'large-video.mp4');
if (attachment.url == null) {
// Check later according to the application's own policy.
final current = await client.media.fetchById(attachment.id);
print(current.url == null ? 'Still processing' : current.url);
}

Updating media attributes​

Update alt text, thumbnail, or focal point before attaching to a status:

final updated = await client.media.update(
attachment.id,
description: 'Updated alt text',
focus: '0.5,0.0',
);

Deleting unattached media​

Only media not yet attached to a status can be deleted:

await client.media.delete(attachment.id);

API version fallback​

The library prefers POST /api/v2/media and automatically falls back to POST /api/v1/media for servers that do not support v2 (HTTP 404, 405, or 501). This is handled transparently.

Attaching to a status​

final attachment = await client.media.upload(bytes, 'photo.jpg',
description: 'A scenic view',
);

final result = await client.statuses.create(
MastodonStatusCreateRequest(
status: 'Check out this view!',
mediaIds: [attachment.id],
),
);

Up to 4 images or 1 video/audio can be attached per status (server-dependent).