A JSONL ledger for image edits: model, prompt, cost and URL on Sume

Every paid image edit should leave one line: model, prompt, references, status, usage.cost and result URL. 25 lines of Python make that audit trail.

5 min readSume
All posts

When four vendors ship better editing in the same month, teams try all four and then cannot say which edit came from where. The cure is dull and cheap: one JSON line per paid call. Sume gives you most of the fields. A completed request returns usage.cost, the billed USD amount, and the model you asked for; a slow one returns 202 with a job id and a status URL (Sume Image API).

What to write down

Sume stores metadata on the job and does not send it to the provider, so it is a safe place for your own ids.

Fields for an image-edit ledger line, from Sume docs, read 2026-10-04
FieldWhere it comes fromWhy keep it
modelYour request (echoed in the response)Which family made the image
prompt, referencesYour requestReproduce or audit the edit
http_statusThe response200 is a result, 202 is a job
usage.costResponse on 200What you were billed
job id and status_url202 envelopeRecover the result later
metadataRequest field Sume stores on the jobTie the edit to your ticket or SKU

The wrapper

Call it with a request body and a ref such as an order id. On a 202, read the finished job from status_url and result URL later, then append a second line.

import json
import os
import time
import requests

H = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}

def edit(body: dict, ref: str, ledger: str = "edits.jsonl") -> dict:
    body = {**body, "metadata": {"ref": ref}}
    r = requests.post("https://api.sume.com/v1/images", headers=H, json=body, timeout=90)
    out = r.json()
    line = {"t": int(time.time()), "ref": ref, "model": body["model"],
            "prompt": body["prompt"], "status": r.status_code}
    if r.status_code == 200:
        line["cost"] = out["usage"]["cost"]
        line["urls"] = [d["url"] for d in out["data"]]
    elif r.status_code == 202:
        line["job"] = out["data"]["job"]["id"]
        line["status_url"] = out["data"]["status_url"]
    with open(ledger, "a") as f:
        f.write(json.dumps(line) + "\n")
    return out

Using the ledger

A ledger is only useful if every call goes through the wrapper, so make it the only function that touches the API.

  • Sum cost by model to see what each family costs you.
  • Filter by ref to answer why this image looks like this.
  • Count 202 lines to see how often your settings outgrow the 30-second wait.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume