What the Higgsfield API actually exposes, and what only the app does
The platform API and the website sell different products under the same brand. We found that out by building against the website. This page is the reference we wanted: every endpoint, its real options, and the four routes that exist on the wire but not in the spec you would generate a client from.
Measured against docs.higgsfield.ai/docs/openapi.json and higgsfield.ai on 22 August 2026. Every number below can be reproduced with the two commands in the next section. Where a fact came from a dated run rather than from today, it says so on the line.
The whole API in six numbers
The spec calls itself Higgsfield API 2.0.0 and names one server,
https://platform.higgsfield.ai. It declares fifty operations across fifty paths.
Two of those are request management. The other forty-eight are models.
The last three of those are the ones that change a plan. If you are reselling generation, you cannot tell a customer what they bought from over half this catalogue — the request schema simply has no resolution field, so there is nothing to promise and nothing to check. No video endpoint anywhere in the fifty offers anything above 1080p.
Reproduce every number on this page
The spec is public and needs no key. Counting it takes one command, and the endpoint tables further down are the same document printed differently.
# the endpoint count
curl -s https://docs.higgsfield.ai/docs/openapi.json \
| python3 -c "import sys,json;d=json.load(sys.stdin);\
print(sum(1 for p in d['paths'] for m in d['paths'][p] if m in ('get','post')))"
50
# every path, with the option lists this page tabulates
curl -s https://docs.higgsfield.ai/docs/openapi.json > hf.json
python3 - <<'PY'
import json
d = json.load(open('hf.json'))
C = d['components']['schemas']
def deref(s):
while isinstance(s, dict) and '$ref' in s: s = C[s['$ref'].split('/')[-1]]
return s if isinstance(s, dict) else {}
for path in sorted(d['paths']):
op = list(d['paths'][path].values())[0]
body = op.get('requestBody', {}).get('content', {}).get('application/json', {})
props = deref(body.get('schema', {})).get('properties', {})
fields = {k: deref(v).get('enum') for k, v in props.items()}
print(path, {k: v for k, v in fields.items() if v})
PY
Save the spec before you read it. It changes without a changelog entry — see the drift section, where two endpoints gained aspect ratios in five days while the published changelog stayed on 11 August.
The website and the API are different products
This is the trap, and it is the expensive one. The names on
higgsfield.ai are not the names on platform.higgsfield.ai. A
specification written from the marketing site will name models that the API has never
carried, and the mismatch does not surface until a request comes back
404 model_not_found — by which time the pipeline is built.
| Named on higgsfield.ai, 22 Aug 2026 | On the platform API | Nearest thing the API does carry |
|---|---|---|
| GPT Image 2 | Absent | Nothing from OpenAI on the image side at all |
| Nano Banana Pro | Absent | /nano-banana — the plain path, no Pro tier, and no resolution field |
| Seedream 5 | Absent | Nothing |
| Kling O1 | Absent | /kling-video/v2.1/* and /kling-video/v2.5-turbo/* |
| Seedance 2.5, in 1080p | Absent | /bytedance/seedance/v1/lite/* and /v1/pro/fast/*. There is no 2.0 and no 2.5 here |
| Cinema Studio 4.0 | Absent | Nothing. It is an app surface |
| Viral Presets — comic, ink riot, bullet time and the rest | Absent | /higgsfield-ai/dop/* takes a motions array keyed by preset identifiers, which the API never gives you |
| Marketing Studio | Absent | Nothing |
| Native 4K output | One path only | /higgsfield-ai/soul/standard accepts 2K or 4K. Every video endpoint stops at 1080p |
| FLUX | Present | /flux-pro/kontext/max/text-to-image, one endpoint |
| Higgsfield Soul | Present | /higgsfield-ai/soul/standard, /soul/reference, /soul/character |
Left column read off higgsfield.ai and higgsfield.ai/image on 22 August 2026; right column from the OpenAPI document fetched the same day. "Absent" means absent from the spec — not that the model does not exist. All of these are real products inside the app. They are simply not addressable over the platform API.
This cost us twice on the same pipeline
A film pipeline here was specified against Seedance 2.5 at 1080p or 4K, because that is what the website advertises. Neither half exists on the API: there is no Seedance above v1, and no video endpoint of any kind returns 4K. The pipeline was rebuilt against Veo 3.1, which is in the spec, has seven endpoints, and pins both ends of a shot — the best coherence available for a multi-shot film.
Then the price probe ran. On 17 August 2026, from a Cloudflare Worker against a funded
account, three of the five models we priced answered 404
model_not_found — Veo 3.1 among them, along with Seedance v1 pro/fast and
Sora 2 Pro. Only Kling 2.5 Turbo Pro and Wan 2.5 quoted a price. The house model had been
chosen twice and was unreachable both times.
Being in the spec is not being routed to your account
The spec is a catalogue of what the platform can address. It is not a statement about
what your key can reach. Higgsfield's own error table says so in the quietest possible
words: 404 means the request or model was not found for this account.
The clearest case we hit is /nano-banana. It is in the spec today, it was in
the spec on 17 August, and on that date POST /estimate/nano-banana answered
404 {"detail":"model_not_found"} on a paid key. Our document pipeline was
pointed at it. Every picture in every generated document would have failed silently and
shipped a text-only file with an apology, and nothing caught it because no job had ever
run.
You cannot probe for this without a key
The obvious instinct is to check a path before committing to it. That does not work, and it is worth knowing why before you write the probe. Authentication is evaluated before routing, so an unauthenticated request to a real path and to a nonsense path are indistinguishable:
$ for p in /estimate/nano-banana /estimate/veo3.1 /models /estimate/not-a-real-model; do
curl -s -o - -w " %{http_code}\n" -X POST -H 'content-type: application/json' \
-d '{"prompt":"x"}' "https://platform.higgsfield.ai$p"
done
{"detail":"Invalid credentials"} 401
{"detail":"Invalid credentials"} 401
{"detail":"Invalid credentials"} 401
{"detail":"Invalid credentials"} 401 <- a path that does not exist
Run on 22 August 2026 with no credentials. Four paths, one of them invented, four identical answers. A 401 from this API tells you nothing about whether the model is there.
With a key, the price endpoint becomes the probe. POST /estimate/<model
path> answers 404 model_not_found when the path is not routed for you,
and a price or a validation complaint when it is. An estimate is a question about a price,
not an order, so the check costs nothing. If you are running generation in production, this
is the call to make on a schedule — a retired or renamed model otherwise arrives as a 404
that reads exactly like an outage.
Four routes you will not get from the spec
The OpenAPI document declares exactly two query or path parameters in the whole file, both
of them request_id. Everything else in the table below is described in the
prose documentation, or answers on the wire, and appears nowhere in the machine-readable
spec. Generate a client from openapi.json and none of it exists.
| Surface | Where it is | What it does |
|---|---|---|
POST /estimate/<model path> | Prose docs only | Takes the same body as the generation request and returns credits and
usd before you spend anything. The single most useful route on the platform, and the one a generated client will not have |
POST /files/generate-upload-url | Prose docs only | Returns a presigned upload_url, a public_url to pass back as
image_url, and headers you must send verbatim. The upload URL expires after an hour |
?hf_webhook=<https url> | Prose docs only | A query parameter on any generation POST. Delivers the terminal result instead of making you poll. Not declared as a parameter on any of the 48 model paths |
GET /models | Neither — it answers on the wire | The account's own catalogue, where each entry's slug is the request path. Not in the spec, not in the docs index, and therefore carrying no compatibility promise at all |
The first three are documented at docs.higgsfield.ai under Core concepts; the fourth we call from our own code. We have not published its response here because we did not keep a copy — a code comment in our repository records thirteen entries on the day it was run, and one undated count is not a fact worth putting in a reference.
The response schema contradicts the webhook documentation
The spec defines MediaOutput with additionalProperties: false and
exactly one property, url. The webhook documentation shows deliveries carrying
url and content_type in the same object. A client generated
strictly from the spec, validating responses, will reject the payload the documentation tells
you to expect. Parse loosely on the way in.
The API reference itself is candid about the split. It covers status and cancel only, and says the model request schemas are being redesigned and are deliberately not listed. That is a fair warning, and it means the 48 model paths in the spec carry no stability promise.
The eleven image endpoints
Every option below is the enum from the request schema, with the default in brackets. "Not stated" means the field does not exist on that endpoint — you cannot ask, and the reply will not tell you.
| Path | Resolution | Aspect ratios | Per request | Required beyond prompt |
|---|---|---|---|---|
| /higgsfield-ai/soul/standard | 2K, 4K (2K) | 1:1 4:3 3:4 3:2 2:3 5:4 4:5 16:9 9:16 21:9 | 1–4 | — |
| /higgsfield-ai/soul/reference | 720p, 1080p (720p) | 9:16 16:9 4:3 3:4 1:1 2:3 3:2 | 1 or 4 | image_reference_url |
| /higgsfield-ai/soul/character | 720p, 1080p (720p) | 9:16 16:9 4:3 3:4 1:1 2:3 3:2 | 1 or 4 | custom_reference_id, custom_reference_strength |
| /higgsfield-ai/popcorn/auto | 720p, 1600p (720p) | 1:1 4:3 3:4 3:2 2:3 16:9 9:16 | 1–8 | — |
| /nano-banana | Not stated | auto 1:1 4:3 3:4 3:2 2:3 5:4 4:5 16:9 9:16 21:9 | 1–4 | — |
| /flux-pro/kontext/max/text-to-image | Not stated | 16:9 4:3 1:1 3:4 9:16 2:3 1:2 2:1 4:5 3:2 | 1 | — |
| /reve/text-to-image | Not stated | Not stated | 1–4 | — |
| /reve/remix | Not stated | 1:1 4:3 3:4 3:2 2:3 5:4 4:5 16:9 9:16 | 1–4 | image_urls |
| /reve/fast/remix | Not stated | 1:1 4:3 3:4 3:2 2:3 5:4 4:5 16:9 9:16 | 1–4 | image_urls |
| /reve/edit | Not stated | Not stated | 1–4 | image_url |
| /reve/fast/edit | Not stated | Not stated | 1–4 | image_url |
Three details that bite. Soul reference and character take
batch_size, and its enum is literally 1 or 4 — not a range, so 2 and 3 are
rejected. Seven of the eleven state no resolution, including every Reve path and
nano-banana. And /flux-pro/kontext/max/text-to-image carries
safety_tolerance with a default of 6, which is the maximum the field allows.
The thirty-seven video endpoints
Grouped by family. Duration is in seconds. Where a family shares its options across every endpoint, the difference between the rows is only what you must supply.
| Path | Resolution | Duration | Aspect | Required beyond prompt |
|---|---|---|---|---|
| Veo 3.1 — Google. The only family that can generate its own audio, and the only one that pins both ends of a shot. | ||||
| /veo3.1 | 720, 1080 (720) | 4, 6, 8 (6) | 16:9 9:16 | resolution, aspect_ratio, generate_audio |
| /veo3.1/fast | 720, 1080 (720) | 4, 6, 8 (6) | 16:9 9:16 | resolution, aspect_ratio, generate_audio |
| /veo3.1/image-to-video | 720, 1080 (720) | 4, 6, 8 (6) | 16:9 9:16 | image_url |
| /veo3.1/fast/image-to-video | 720, 1080 (720) | 4, 6, 8 (6) | 16:9 9:16 | image_url |
| /veo3.1/first-last-frame-to-video | 720, 1080 (720) | 4, 6, 8 (6) | 16:9 9:16 | first_frame_url, last_frame_url |
| /veo3.1/fast/first-last-frame-to-video | 720, 1080 (720) | 4, 6, 8 (6) | 16:9 9:16 | first_frame_url, last_frame_url |
| /veo3.1/reference-to-video | 720, 1080 (720) | 4, 6, 8 (6) | 16:9 9:16 | image_urls |
| Sora 2 — OpenAI. The plain pair caps at 720p; only the pro pair reaches 1080p. | ||||
| /sora-2/text-to-video | 720p only | 4, 8, 12 (4) | 16:9 9:16 | — |
| /sora-2/image-to-video | 720p only | 4, 8, 12 (4) | 16:9 9:16 | — (image_url is optional here) |
| /sora-2/text-to-video/pro | 720p, 1080p (720p) | 4, 8, 12 (4) | 16:9 9:16 | — |
| /sora-2/image-to-video/pro | 720p, 1080p (720p) | 4, 8, 12 (4) | 16:9 9:16 | image_url |
| Seedance v1 — ByteDance. The only family with a duration range rather than a list, and the only one offering 21:9. | ||||
| /bytedance/seedance/v1/pro/fast/text-to-video | 480, 720, 1080 (1080) | 2–12 (5) | 16:9 9:16 4:3 3:4 1:1 21:9 | — |
| /bytedance/seedance/v1/pro/fast/image-to-video | 480, 720, 1080 (1080) | 2–12 (5) | 16:9 9:16 4:3 3:4 1:1 21:9 | image_url |
| /bytedance/seedance/v1/lite/text-to-video | 480, 720, 1080 (720) | 2–12 (5) | 16:9 9:16 4:3 3:4 1:1 21:9 | — |
| /bytedance/seedance/v1/lite/image-to-video | 480, 720, 1080 (1080) | 2–12 (5) | 16:9 9:16 4:3 3:4 1:1 21:9 | image_url |
| Wan 2.5 preview — Alibaba. The only endpoints that accept a supplied audio track. Marked preview by the provider. | ||||
| /wan-25-preview/text-to-video | 480p, 720p, 1080p (720p) | 5, 10 (5) | Not stated | — (audio_url optional) |
| /wan-25-preview/image-to-video | 480p, 720p, 1080p (720p) | 5, 10 (5) | Not stated | image_url |
Kling — Kuaishou. Seven endpoints, none of which states a resolution. All carry cfg_scale (0–1, default 0.5) and negative_prompt. | ||||
| /kling-video/v2.5-turbo/pro/text-to-video | Not stated | 5, 10 (5) | Not stated | — |
| /kling-video/v2.5-turbo/pro/image-to-video | Not stated | 5, 10 (5) | Not stated | image_url |
| /kling-video/v2.5-turbo/standard/image-to-video | Not stated | 5, 10 (5) | Not stated | image_url |
| /kling-video/v2.1/master/text-to-video | Not stated | 5, 10 (5) | 1:1 16:9 9:16 (1:1) | — |
| /kling-video/v2.1/master/image-to-video | Not stated | 5, 10 (5) | Not stated | image_url |
| /kling-video/v2.1/pro/image-to-video | Not stated | 5, 10 (5) | Not stated | image_url |
| /kling-video/v2.1/standard/image-to-video | Not stated | 5, 10 (5) | Not stated | image_url |
MiniMax Hailuo — ten endpoints. Every pro tier states neither resolution nor duration. All carry prompt_optimizer, default true. | ||||
| /minimax/hailuo-02/standard/image-to-video | 512P, 768P (768P) | 6, 10 (6) | Not stated | image_url (end_image_url optional) |
| /minimax/hailuo-02/standard/text-to-video | Not stated | 6, 10 (6) | Not stated | — |
| /minimax/hailuo-02/pro/image-to-video | Not stated | Not stated | Not stated | image_url |
| /minimax/hailuo-02/pro/text-to-video | Not stated | Not stated | Not stated | — |
| /minimax/hailuo-2.3/standard/image-to-video | Not stated | 6, 10 (6) | Not stated | image_url |
| /minimax/hailuo-2.3/standard/text-to-video | Not stated | 6, 10 (6) | Not stated | — |
| /minimax/hailuo-2.3/pro/image-to-video | Not stated | Not stated | Not stated | image_url |
| /minimax/hailuo-2.3/pro/text-to-video | Not stated | Not stated | Not stated | — |
| /minimax/hailuo-2.3-fast/standard/image-to-video | Not stated | 6, 10 (6) | Not stated | image_url |
| /minimax/hailuo-2.3-fast/pro/image-to-video | Not stated | Not stated | Not stated | image_url |
DoP — Higgsfield's own. Three tiers, no resolution, no duration, no aspect. Takes a motions array of preset objects. | ||||
| /higgsfield-ai/dop/turbo | Not stated | Not stated | Not stated | image_url (end_image_url, motions optional) |
| /higgsfield-ai/dop/standard | Not stated | Not stated | Not stated | image_url |
| /higgsfield-ai/dop/lite | Not stated | Not stated | Not stated | image_url |
The spec does not declare an output type for any endpoint, so the image/video split above is ours. We placed DoP with video because it takes a first and a last frame and a motions list; we have not run it, and we say so rather than assert it.
Veo requires three fields that its own siblings make optional
/veo3.1 and /veo3.1/fast mark resolution,
aspect_ratio and generate_audio as required. The five
other Veo endpoints mark the same three optional, with the same defaults. Send the body
that works for /veo3.1/image-to-video to /veo3.1 and you get a
422. There is nothing in the naming to warn you.
And generate_audio defaults to false on every Veo path. The
one family on this API that can produce sound has sound switched off unless you ask.
One field, eight vocabularies
There is no shared convention for resolution or duration across the forty-eight model endpoints. This is not a nitpick: send the wrong spelling and the request is rejected, and a mapping table written from one family's schema will silently mis-handle another's. Here is every distinct enum in the spec, with how many endpoints carry it.
| Field | The exact values accepted | Endpoints | Who uses it |
|---|---|---|---|
| resolution | 720, 1080 | 7 | Veo 3.1 |
| resolution | 480, 720, 1080 | 4 | Seedance v1 |
| resolution | 720p, 1080p | 4 | Sora 2 Pro, Soul reference, Soul character |
| resolution | 480p, 720p, 1080p | 2 | Wan 2.5 |
| resolution | 720p | 2 | Sora 2, non-pro |
| resolution | 512P, 768P | 1 | Hailuo 02 standard image-to-video |
| resolution | 720p, 1600p | 1 | Popcorn |
| resolution | 2K, 4K | 1 | Soul standard |
| resolution | absent | 26 | Kling, Reve, nano-banana, Flux, DoP, most Hailuo |
| duration | 5, 10 | 9 | Kling, Wan |
| duration | 4, 6, 8 | 7 | Veo 3.1 |
| duration | 6, 10 | 5 | Hailuo standard tiers |
| duration | 4, 8, 12 | 4 | Sora 2 |
| duration | any integer 2 to 12 | 4 | Seedance v1 |
| duration | absent | 8 video | DoP, every Hailuo pro tier |
Four notations for one idea: a bare integer, a lower-case p, an upper-case P,
and K-notation. Veo wants 1080; Sora wants 1080p; Hailuo wants
768P. Duration is worse, because the wire type also moves — Veo takes the
string, the others take the number.
The spec moves without a changelog entry
We captured five endpoint schemas on 17 August 2026 and re-fetched the whole document on 22 August. All five paths are still there, with the same required fields. Two of them accept aspect ratios today that they did not list five days ago.
| Endpoint | Aspect ratios, 17 Aug | Aspect ratios, 22 Aug | Change |
|---|---|---|---|
| /nano-banana | auto 1:1 4:3 3:4 3:2 2:3 5:4 4:5 | auto 1:1 4:3 3:4 3:2 2:3 5:4 4:5 16:9 9:16 21:9 | 8 → 11 |
| /higgsfield-ai/soul/standard | 1:1 4:3 3:4 3:2 2:3 5:4 4:5 16:9 | 1:1 4:3 3:4 3:2 2:3 5:4 4:5 16:9 9:16 21:9 | 8 → 10 |
| /higgsfield-ai/soul/reference | 9:16 16:9 4:3 3:4 1:1 2:3 3:2 | 9:16 16:9 4:3 3:4 1:1 2:3 3:2 | unchanged |
| /bytedance/seedance/v1/pro/fast/text-to-video | 16:9 9:16 4:3 3:4 1:1 21:9 | 16:9 9:16 4:3 3:4 1:1 21:9 | unchanged |
| GET /requests/{request_id}/status | n/a | n/a | schema unchanged |
The published changelog's most recent entry on 22 August 2026 is dated 11 August, and mentions no schema change. It does carry a note saying model availability and model-specific schema changes will be documented with a redesigned model catalogue — which is honest, and also means there is no notification channel for this today. Diff the spec yourself on a schedule.
What we cannot tell you about the drift
We did not keep a full copy of the spec on 17 August — only the five schemas above, extracted for a build. So we cannot say whether the endpoint count moved in those five days. It is fifty today. Anyone claiming to know what it was on the 17th from this page is reading something we did not write.
Billing, retention and failure, as they actually behave
Four behaviours matter more than the rest, and three of them are in your favour.
Ask the price before you spend it
Prefix any model path with /estimate, send the body you were going to send,
and you get credits and dollars back. Not a similar body — the same one, because a
price quoted against a slightly different request is not the price of the thing you are
buying.
curl -X POST https://platform.higgsfield.ai/estimate/higgsfield-ai/soul/standard \
-H "Authorization: Key ${HF_API_KEY_ID}:${HF_API_KEY_SECRET}" \
-H "Content-Type: application/json" \
-d '{"prompt":"...","aspect_ratio":"4:3","resolution":"2K"}'
{"credits": "1.500", "usd": "0.094"}
Response shape from Higgsfield's own billing documentation. The figures returned for your account are the authoritative ones — never hard-code a rate card from a sample.
Failed and moderated work is free
A request that ends failed or nsfw is not charged, and reserved
credits are refunded automatically. A queued request cancelled before processing starts is
refunded too — but cancellation is only possible while every job in the request is still
queued; once it is in_progress, cancel returns 400. Practically: be generous
with retries, and do not build a cancel button you cannot honour.
Seven days, then it is gone
Output is accessible for at least seven days and may be removed after that. Copy every completed file into your own storage on the same tick you receive it. A URL stored instead of the bytes is a customer library that empties itself a week later. Credits themselves expire one year after they are added.
The concurrency error is a 400, not a 429
Hit your account's concurrency ceiling and the API returns 400 Bad Request
with a message naming the limit. There are no standard rate-limit headers and no
Retry-After. Retry logic keyed on 429 will treat a queue-full condition as a
malformed request and give up. There is also no idempotency key on submissions, so an
ambiguous timeout on a generation POST must not be retried blindly — poll instead.
What generation actually cost us
Measured against /estimate on a funded account, converted at Higgsfield's
top-up rate of about $0.05 a credit, which is the conservative figure — the subscription rate
is cheaper. These are indicative estimates, not quotes, and they will move whenever the
provider's rate card does.
| What we generated | Cost to us | Made of |
|---|---|---|
| One image | ~$0.10 | Two Higgsfield credits at 2K |
| A branded document | ~$0.44 | About four images, plus ~$0.04 of language-model tokens |
| A slide deck | ~$1.03 | About ten images, plus tokens |
| 60 seconds of film, Kling 2.5 Turbo Pro | ~$4.20 | Quoted by /estimate, 17 Aug 2026 |
| 60 seconds of film, Wan 2.5 | ~$9.00 | Quoted by /estimate, 17 Aug 2026 |
Film is the outlier by roughly sixty times. Every other line is rounding error against its price; film is the only one where a few extra takes moves the margin. If you are pricing a product on this API, that single ratio should decide your unit economics before anything else does.
Cost is not the only number worth measuring before you commit. We also timed the wall clock on the deck pipeline these images feed: 58 real presentations, median 4 minutes 40 seconds, with the full distribution and the slowest run published rather than hidden.
What we could not determine
A reference that only lists what it knows is easy to trust and easy to misread. These are the gaps, stated plainly, so nobody builds on a silence.
- Which models any given key can reach. Routing is per account. Our 404s on Veo
3.1, Seedance v1 pro/fast and Sora 2 Pro are a fact about one account on 17 August 2026
and about nothing else. Probe with
/estimateagainst your own key before you design around a model. - Whether the endpoint count moved between 17 and 22 August. We kept five schemas, not the whole document. It is fifty today.
- What the 26 endpoints with no resolution field actually return. We did not measure output dimensions, so we do not state them. If you are reselling, this is the first thing to test.
- Whether DoP is video. The spec declares no output type. We infer it from
end_image_urlandmotions. We have not run it. - Where the audio and 3D endpoints are. The completed-request schema carries
audioandaudiosfields, and the webhook documentation mentionsfbx,ply,zip,movandjsxartifacts. No path in the fifty produces any of them. Either they arrive with the redesigned catalogue, or they are reachable only through the app. - The contents of
GET /models. It answers, its slugs are request paths, and we did not keep the response.
If one thing survives this page
Save the spec, diff it on a schedule, and probe /estimate against your own
key before you commit an architecture to a model name. Both cost nothing. Between them
they would have saved us a rebuilt film pipeline and every picture in a fortnight of
generated documents.
We run this API in production for BATech Studio, which reads a customer's own website and returns an editable PowerPoint file. If you are building something similar and want to compare notes, or you want the parts of this we have not written up, the address is at the bottom of the page. Corrections are welcome and will be dated when applied.
The rest of what this pipeline taught us
- Building .pptx by hand: what PowerPoint accepts, and what silently breaks — the file format on the other end of these images, including which applications honour an embedded font and which quietly do not.
- How long an AI presentation takes: 58 timed, median 4m40s — the wall-clock distribution for the pipeline these endpoints feed.
- Why AI decks look the same: 52,488 variations, one studio — what happened when blind reviewers judged output that could be drawn tens of thousands of ways.