Sume idempotency: JSON key order is ignored, array order is not

Resending a Sume job with the same fields in a different JSON key order still returns the original job. Changing an array's order or a value gives a 409.

5 min readSume
All posts

When you retry a paid Sume request with the same Idempotency-Key, the API compares your payload with the stored one after normalizing it. Object keys are sorted before comparing, so {"a":1,"b":2} and {"b":2,"a":1} count as the same request. Array order is kept, so [1,2] and [2,1] differ and give 409 idempotency_conflict.

What the match covers

The OpenAPI text says a reuse with the same operation and normalized payload returns the original job with idempotency_hit: true, and a different operation or payload returns 409 idempotency_conflict. In the repo, the comparison hashes the job type and the request through a stable stringify that sorts object keys at every depth.

What counts as a different request (read 2026-10-06)
ChangeSame key gives
Object keys in another orderOriginal job, idempotency_hit: true
Whitespace or formatting of the JSONOriginal job (the body is parsed first)
Array items in another order409 idempotency_conflict
Any value changed409 idempotency_conflict
A different endpoint409 idempotency_conflict

Reproduce the rule locally

This sketch mirrors the sorted-keys normalization so you can test your own request builder. It is an illustration of the rule, not the server code.

const stable = (v) =>
  v === null || typeof v !== "object"
    ? JSON.stringify(v)
    : Array.isArray(v)
      ? `[${v.map(stable).join(",")}]`
      : `{${Object.keys(v).sort().map((k) => `${JSON.stringify(k)}:${stable(v[k])}`).join(",")}}`;

const a = { prompt: "a red kettle", duration: 5 };
const b = { duration: 5, prompt: "a red kettle" };
console.log(stable(a) === stable(b)); // true: key order ignored
console.log(stable({ x: [1, 2] }) === stable({ x: [2, 1] })); // false: array order counts

Why it matters in a retry wrapper

A wrapper that rebuilds the body from a hash map on each retry may emit keys in a different order. That is safe here. A wrapper that shuffles list inputs, such as reference images, is not safe: build the list once and reuse it.

Never regenerate a payload with a fresh timestamp inside it, because a changed value is a different request.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume