Perl HTTP::Tiny: POST /v1/images on Sume with core modules only

Call Sume's image API from Perl with HTTP::Tiny and JSON::PP, both core modules; handles 200, 202 and errors, with a 40-second timeout.

4 min readSume
All posts

Perl is still common on older servers where you cannot install much, and HTTP::Tiny is enough for this call.

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

Sume POST /v1/images, read 2026-10-07.
StatusMeaningWhat the code below does
200Image finished inside the wait; data[].url holds the filePrints the result
202Wait expired (or mode is async or webhook); body is a job envelope with status_url and result_urlPrints the envelope; poll status_url and read result_url
502The job failed inside the wait; error has code, retryable, next_actionPrints the error
400, 404unsupported_parameter, or model_not_foundPrints the error

Perl code

Save as gen.pl and run SUME_API_KEY=... perl gen.pl. HTTP::Tiny and JSON::PP ship with Perl; HTTPS also needs IO::Socket::SSL installed.

use strict;
use warnings;
use HTTP::Tiny;
use JSON::PP qw(encode_json decode_json);

my $key = $ENV{SUME_API_KEY} or die "SUME_API_KEY missing\n";
my $http = HTTP::Tiny->new(timeout => 40);
my $res = $http->post(
    'https://api.sume.com/v1/images',
    {
        headers => {
            'Authorization' => "Bearer $key",
            'Content-Type'  => 'application/json',
        },
        content => encode_json({
            model        => 'bytedance-seed/seedream-5-lite',
            prompt       => 'matte ceramic mug on a white sweep, soft shadow',
            aspect_ratio => '16:9',
        }),
    }
);
if ($res->{status} == 200) {
    my $out = decode_json($res->{content});
    print "done: $out->{data}[0]{url}\n";
} elsif ($res->{status} == 202) {
    print "queued, follow status_url: $res->{content}\n";
} else {
    print "error $res->{status}: $res->{content}\n";
}

Notes

HTTP::Tiny returns a hash with status and content; it does not die on non-2xx, so the three-way branch is explicit.

Reading $out->{data}[0]{url} is only valid on 200. On 202 the body is a job envelope, not an image list.

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

All Developers posts

Written by Sume