Dart dart:io: POST /v1/images on Sume from a command-line script
A Dart script that calls Sume's image API with dart:io HttpClient, applies a 40-second timeout, and handles 200, 202 and error responses.

A server-side or command-line Dart tool can call the image API with the SDK alone.
The request is the same in every language: POST https://api.sume.com/v1/images with a bearer key from SUME_API_KEY, a JSON body with model, prompt and aspect_ratio, and a client timeout above the route's 30-second wait. The route defaults to mode: "sync", so the status code decides what you do next (docs read 2026-10-07):
Status codes to branch on
| Status | Meaning | What the code below does |
|---|---|---|
| 200 | Image finished inside the wait; data[].url holds the file | Prints the result |
| 202 | Wait expired (or mode is async or webhook); body is a job envelope with status_url and result_url | Prints the envelope; poll status_url and read result_url |
| 502 | The job failed inside the wait; error has code, retryable, next_action | Prints the error |
| 400, 404 | unsupported_parameter, or model_not_found | Prints the error |
Dart code
Save as gen.dart and run SUME_API_KEY=... dart run gen.dart. Only the Dart SDK is needed.
import 'dart:convert';
import 'dart:io';
Future<void> main() async {
final key = Platform.environment['SUME_API_KEY'];
if (key == null || key.isEmpty) {
stderr.writeln('SUME_API_KEY missing');
exit(1);
}
final client = HttpClient()..connectionTimeout = const Duration(seconds: 10);
final req = await client.postUrl(Uri.parse('https://api.sume.com/v1/images'));
req.headers.set('Authorization', 'Bearer $key');
req.headers.contentType = ContentType.json;
req.write(jsonEncode({
'model': 'bytedance-seed/seedream-5-lite',
'prompt': 'matte ceramic mug on a white sweep, soft shadow',
'aspect_ratio': '16:9',
}));
final res = await req.close().timeout(const Duration(seconds: 40));
final text = await res.transform(utf8.decoder).join();
if (res.statusCode == 200) {
print('done: ${jsonDecode(text)['data'][0]['url']}');
} else if (res.statusCode == 202) {
print('queued, follow status_url: $text');
} else {
print('error ${res.statusCode}: $text');
}
client.close();
}Notes
Keep the key on the server. Do not ship SUME_API_KEY inside a Flutter app; call your own backend, which calls Sume.
connectionTimeout covers only the connect step; the .timeout(...) on the response covers the sync wait.
One bytedance-seed/seedream-5-lite image is $0.04375 billed (list $0.035 x 1.25). Prices here are Sume's list-times-1.25 figures. The catalog states the billable formula as "list × 1.25 → ceil usd cents", so treat the dollar amounts as the pre-rounding value and read the exact charge from billable_amount_usd_micros in the submit envelope. Failed or cancelled generations are not billed.
Sources: Sume Image API docs and Jobs and results (read 2026-10-07).
Sources
Related posts
More in Developers
- Sume default queue capacity: max(3, 5 x concurrency), checked per plan
Sume's default queue capacity is max(3, concurrency x 5). Checking the rule against Free, Pro, Startup and Scale, plus the org floor and the wave hint.
- Deno: time out a Sume video submit, then retry with the same key
A fetch that times out may still have created a job. A 20-line Deno submit retries only 408, 429, 5xx and timeouts, always with one Idempotency-Key.
- Idempotency-Key from an order id and version, never a fresh uuid
A fresh uuid per request makes Idempotency-Key do nothing. Derive it from the order id plus a version you bump only to re-run. Scope: one Format, 255 chars.
- How do I narrate a DIY tutorial step by step with a TTS API?
Narrate an 8-step DIY tutorial with one TTS job per step: 1,570 characters, $0.10 on Sume. Why per-step jobs make a fixed step a 1-cent redo.
Written by Sume