Dart: submit a 30-second Wan 3.0 clip with package:http

Server-side Dart with package:http: POST wan-3.0 for 30 seconds, poll until completed and write the MP4. Keep the key out of the Flutter app.

3 min readSume
All posts

Call Sume from Dart on the server, not from the Flutter app: the API key authorises spend, and a 30-second Wan 3.0 job at 720p reserves $3.75. The script below uses package:http to submit wan-3.0, poll the job and save clip.mp4. Run it in a Dart server, a Cloud function or a CLI, and let the app ask your backend for the result.

bin/clip.dart

Add http to pubspec.yaml and run dart run bin/clip.dart with SUME_API_KEY set.

import 'dart:convert';
import 'dart:io';
import 'package:http/http.dart' as http;

Future<void> main() async {
  final key = Platform.environment['SUME_API_KEY'] ?? '';
  if (key.isEmpty) throw StateError('SUME_API_KEY is empty');
  final auth = {'Authorization': 'Bearer $key'};
  const base = 'https://api.sume.com/v1/videos';
  final res = await http.post(Uri.parse(base),
      headers: {...auth, 'Content-Type': 'application/json', 'Idempotency-Key': 'wan-dart-001'},
      body: jsonEncode({
        'model': 'wan-3.0', 'prompt': 'A cyclist crossing a bridge in morning fog',
        'duration': 30, 'resolution': '720p', 'aspect_ratio': '9:16',
      }));
  if (res.statusCode >= 300) throw StateError('submit failed: ${res.statusCode}');
  final id = jsonDecode(res.body)['id'];
  var status = 'pending';
  while (status == 'pending' || status == 'in_progress') {
    await Future.delayed(const Duration(seconds: 5));
    final s = await http.get(Uri.parse('$base/$id'), headers: auth);
    status = jsonDecode(s.body)['status'];
  }
  if (status != 'completed') throw StateError('job ended as $status');
  final mp4 = await http.get(Uri.parse('$base/$id/content?index=0'), headers: auth);
  await File('clip.mp4').writeAsBytes(mp4.bodyBytes);
}

Points to check

  • A missing key throws before any request is made.
  • duration is the integer 30. The wan-3.0 id accepts 2 to 30 seconds according to the Video generation docs.
  • The idempotency key wan-dart-001 is fixed for the demo. Build one per request in real code, for example from the user id and a request counter.

What your app can show the user

Quote the cost before the user taps generate. The per-second rate is constant for each resolution, so the quote is multiplication:

Sume list price for wan-3.0, read 2026-10-08
Length480p720p1080p
5 s$0.3125$0.625$1.25
15 s$0.9375$1.875$3.75
30 s$1.875$3.75$7.50

Where the key lives

A Flutter binary can be unpacked, so any key inside it is public. Store SUME_API_KEY in your server's secret store, authenticate your own users to your own backend, and have the backend submit to Sume. That also lets you enforce a per-user limit before a 30-second job reserves its price.

Return a job id, not a blocked request

Mobile clients should not hold a connection open for the length of a generation. Have your backend return the Sume job id right after the submit, then expose a status endpoint that your app polls, or push a notification when the callback arrives.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume