dangerouslyAllowBrowser: true, because your API key would be readable by
anyone who opens the page.
Why use it instead of the OpenAI SDK
You can point the OpenAI SDK at this gateway, and for chat and embeddings that works. Past those, three things it cannot do for you: Reach endpoints it has no methods for. Video, music, 3D, upscaling, workflows and capabilities are not in the OpenAI API. Neither isPOST /v1/images/edits in the shape this gateway takes it — that endpoint
accepts JSON with the image base64-encoded, while the OpenAI SDK posts
multipart.
Collect a deferred result. A slow media generation answers 504 with a
job_id and keeps working — and keeps billing. An OpenAI SDK caller sees a
failure and pays for nothing. This SDK collects the finished result from the job
endpoint for you.
Retry the right things. Rate limiting here answers 403, not 429, so the
OpenAI SDK’s backoff never fires. And a 500 on a billed POST must NOT be
retried blind, because it may arrive after your balance was already debited.
See OpenAI SDK compatibility for the
endpoint-by-endpoint answer.
What it covers
Every published operation. The namespaces:Streaming
credits_used and an empty
choices array. It is yielded like any other chunk rather than hidden, because
it is the only place the cost of a streamed call appears.
One call for every media modality
Each media modality also has its own method —images.generate,
videos.generate, and the rest below. That is the wrong shape when the modality
is a runtime value: a model picked from the catalogue, a choice in a UI, a row
in a queue. Then every call site needs a switch, and every one of those has to
be edited when a modality is added.
media.generate() takes the modality as data:
The result shape
url, b64 and bytes is set on an artifact, and which one is a
property of the endpoint rather than of your request:
upscale routes on the source, not the model: pass image_url or video_url.
The gateway refuses an image upscaler on the video route and vice versa, and the
model slug alone does not say which it is, so the SDK cannot guess — it asks.
What it gives up
Worth seeing before you choose it, because the named methods are still there and still better when you know the modality:- Named parameter checking.
MediaGenerateParamsis open, so a misspelledduration_secnodscompiles.videos.generate()rejects that one specifically, because the gateway ignores unknown keys and a silent default costs money. withResponse(). There is no honest uniform envelope — video polls a job, so there is no single response to hand back.- Fields with no cross-modality meaning —
revised_prompt,lyrics,resolution. They are onresult.raw.
MediaGenerateParams and MediaResult are on the
reference.
Media that takes minutes
Generation is submitted and awaited inside one request. If the gateway’s own wait runs out it answers504 with a job id and keeps working — the SDK collects
the result:
Workflows
runs.stream() yields a typed event per step:
pipeline_id while the product says Workflow: the rename
stopped at the HTTP boundary, and the SDK types what the wire accepts rather
than inventing a nicer name for it.
Errors
InferyError, so one instanceof
catches all of them. err.requestId is the handle support uses to attribute a
charge — quote it when asking about a bill.
Branch on err.code when the class is not specific enough. ConflictError is
the clearest case: upload_in_progress means retry in a moment, while
idempotency_in_progress means a billed run is already in flight and a retry
could start a second one.
Cancelling and timeouts
Every method that makes a request takes{ signal, timeout }:
Retries
Connection failures,408/429/5xx and 409 upload_in_progress are retried
with exponential backoff — but only on a GET or on the two endpoints that
honour Idempotency-Key (POST /v1/files, POST /v1/workflows/runs). On every
other billed POST, a 500 is not retried: the gateway collapses several
distinct upstream failures, including ones that happen after your balance was
debited, into the same generic 500, and retrying blind risks paying twice.
Two things are never retried. 403 rate_limit_exceeded is a 60-second sliding
window that counts refused requests too, so retrying inside it pushes your own
recovery further out. And any response carrying a job_id means the work exists
and is already billed — the SDK collects it rather than paying for a second one.
Reference
- Package:
@infery/sdk - Source:
sdks/typescript - Browsable build: infery-typescript
- Endpoint-by-endpoint OpenAI SDK compatibility