Skip to main content

Model Endpoints

Every model on FlyMy.AI is addressed by its endpoint id, written as {owner}/{model} - for example flymyai/google-gemini-25-flash. The endpoint id maps directly into the URL path.

https://api.flymy.ai/api/v1/{owner}/{model}/{route}

Authentication​

All routes take an API key in the X-API-KEY header:

-H "X-API-KEY: fly-***"

Create keys in your FlyMy.AI account settings. A key can call any public model plus every model you own.

Routes​

RoutePurpose
POST /predictRun the model and wait for the complete result
POST /predict/stream/Run the model and receive the result incrementally over SSE
POST /predict/async/Queue the run and return its prediction_id immediately
GET /predict/async/result/?request_id=<prediction_id>Fetch the result of a queued run; POST here returns 405 Method Not Allowed
POST /predict/cancel/Cancel a running prediction by its prediction_id
GET /openapi.jsonThe model's own schema: exact inputs, types, and output fields

Not every model supports every route. Text generation models are streaming-only and reject /predict; see Using LLMs.

Retrying an async run safely​

Send an Idempotency-Key header with POST /predict/async/ when a retry must not start a second paid run. The key is 1-255 printable ASCII characters with no leading or trailing spaces; use a new key for each run you intend.

curl -X POST https://api.flymy.ai/api/v1/flymyai/nano-banana/predict/async/ \
-H "X-API-KEY: fly-***" \
-H "Idempotency-Key: icon-run-7f3c2a" \
-F "prompt=A blue circle, flat icon"
  • Same key, same input: 202 with the first run's prediction_id. Nothing runs or is charged again.
  • Same key, other input: 409 with code: idempotency_key_reused, before anything runs.
  • The first request is still being submitted: 409 with code: idempotency_key_in_flight. Send the same request again a moment later.
  • The first submission broke off after the run may have started: 409 with code: tool_outcome_unknown. The run may exist, so check your results before starting it again under a new key.

Without the header every request queues a new run. /predict and /predict/stream/ do not keep keys. The Agents MCP run_model sends its operation_key as this header for image and video models.

Discovering a model's inputs​

Rather than guessing parameter names, read the schema the model publishes:

curl -H "X-API-KEY: fly-***" \
https://api.flymy.ai/api/v1/flymyai/google-gemini-25-flash/openapi.json

The input fields live under components.schemas.DynamicInputModel, and the output fields under DynamicOutputModel. A field's description states its limits when the model has them, such as allowed durations, file types or a minimum video size. An output field marked "isStream": true means the value is delivered progressively and the model should be called through /predict/stream/.

Request format​

Requests are sent as form data, not JSON - this is what allows file inputs such as images and audio to travel in the same request as text parameters.

curl -X POST \
https://api.flymy.ai/api/v1/flymyai/google-gemini-25-flash/predict/stream/ \
-H "X-API-KEY: fly-***" \
-F "prompt=Hello"

A JSON body returns 422 Field required even when the JSON itself is valid.

A list input goes as one field per item, and an object as its JSON text:

curl -X POST \
https://api.flymy.ai/api/v1/flymyai/gemini-3_8-flash-vlm/predict \
-H "X-API-KEY: fly-***" \
-F "prompt=How many photos show a dog?" \
-F "media_url=https://example.com/1.jpg" \
-F "media_url=https://example.com/2.jpg" \
-F 'response_schema={"type":"object","properties":{"count":{"type":"integer"}}}'

The Python SDK (flymyai 1.2.0rc10 and later) sends lists and objects this way for you.

Response format​

Synchronous​

/predict returns a single JSON document with the model's outputs under output_data.

Streaming​

/predict/stream/ returns a Server-Sent Events stream. The first event acknowledges the request and carries the prediction_id used for cancellation:

event: {"prediction_id":"f9e443caf50e..."}

Content events follow, each carrying a fragment of the output:

data: {"output_data":{"output":["first fragment "]},"status":200}

The stream closes with a final event whose output_data is empty and which carries usage information. For token-priced models this is stream_details with the token counts the charge is computed from:

data: {"output_data":{},"status":200,"stream_details":{"input_tokens":15,"output_tokens":49}}

Disable client-side buffering when consuming a stream, otherwise your HTTP client may hold the fragments and hand you the whole response at the end. With curl, pass -N.

Errors​

Transport-level failures use standard HTTP status codes. Some conditions are reported inside a 200 response body with their own status_code field, so check the payload rather than the HTTP status alone:

{"detail":"Predict is not available for current pipeline. Use /predict/stream route instead!","status_code":421}
StatusMeaning
403 API key does not have access to the projectModel is private and you are not its owner
403 Insufficient fundsWallet balance is negative
403 Project is not activeThe project has no capacity allocated
404 Project not foundThe endpoint id does not exist
422 Field requiredA required parameter is missing, or the body was sent as JSON

When a model refuses the request itself, the message stays in detail and, if the model says why, reason comes next to it - for example a Vision prompt over its 100,000-character limit:

{"output_data":{"detail":"Vision API returned HTTP 400","reason":"... String should have at most 100000 characters [string_too_long]"},"status":400}

Keep matching on the status and detail; reason is for people and logs, and a refusal without one looks as before.

See Errors for the full list.

Typed decisions​

For fast classification, routing, triage, fixed-enum extraction and yes/no gates, use TypeSafe Jev 1.13. It accepts state and typed questions through its JSON Decisions endpoint and returns Choice, Noul probability or Score answers. It is not a chat model and does not generate prose, code or media. Both MCP servers expose make_typed_decision; agents discover typesafe_jev.decide.