There is no model field in an Auray request body. The model is the path.
POST https://queue.auray.run/auray-ai/krea-2-turbo/text-to-image
└────┬────┘ └──────┬──────┘ └───┬───┘
namespace model taskThe namespace first, then the model, and usually the task — two to six segments in all. No v1 in
front of the model, no per-model client library.
#What this buys
A name you read anywhere is immediately callable. Someone mentions an address in a changelog
entry or a support thread; you can curl it without looking anything up first. The name and the
URL are the same string, so there is nothing to translate.
A request body is only parameters. Nothing in it identifies what is running. Switching models
means changing the URL — not rewriting the payload around a different model value and hoping the
rest of the fields still apply.
The shape does not change between addresses. Whatever you learn calling one applies to the next: the same auth, the same job lifecycle, the same webhook signature, the same error vocabulary. 401 addresses across 16 namespaces, reached identically.
#The version we did not add
The usual next step is a version of our own on every address — …/text-to-image/v2 — and it is a
trap worth naming.
A version of ours in the path means every caller has to decide when to move, which means the old version has to keep running, which means a catalogue that only grows. It also means the interesting question — is this address still the right one? — is answered by a number rather than by the service.
A vendor's own version is a different thing. veed/lipsync/v2 is that vendor's name for its second
lip-sync model, and it sits beside veed/lipsync the way two models with different names do: each is
an address, each is described on its own. We add no version of ours on top of either.
Instead, an address we retire answers:
{
"error": "model_deprecated",
"successor": "auray-ai/krea-2-turbo/text-to-image",
"deprecated_at": "2026-09-10T00:00:00Z",
"docs": "https://auray.ai/docs/api/errors#model_deprecated",
"request_id": "54b4754a-3e17-4629-adb1-7d3f067e97d3"
}An integration written against something withdrawn fails loudly with the fix in the body. The
failure mode we were avoiding is the other one: a model quietly changing underneath an address
that still returns 200, so the output drifts and nothing anywhere says why.
#Finding out what an address accepts
Every address publishes its own parameter list — types, defaults, bounds — so you can validate a request before spending anything on it:
curl "https://api.auray.ai/v1/models/auray-ai/krea-2-turbo/text-to-image/openapi.json" \
-H "Authorization: Bearer $AURAY_API_KEY"353 of the 401 addresses have a published shape today. The rest are named and reserved: the address exists, and it refuses rather than guessing at your body.
#The one thing to be careful about
GET /v1/models reports which addresses are generating right now, and that answer changes as
capacity switches on. It is the only current answer — do not cache it for long, and do not treat
"described" as "available". The catalogue tells you which is which on every request.
More in Addresses.
Filed under Product on All posts