Models
Listing available models and using the current chat, image, and video models.
List models#
GET /openai/v1/modelscurl https://api.portmodels.com/openai/v1/models \
-H "Authorization: Bearer $PORTMODELS_API_KEY"{
"object": "list",
"data": [
{
"id": "model-owner/example-model",
"object": "model",
"created": 1700000000,
"owned_by": "model-owner",
"root": "model-owner/example-model",
"parent": null
}
]
}The id is the model key — the exact string to send as model in a
chat completion. owned_by identifies the
model's owner.
Get one model#
GET /openai/v1/models/{model_key}curl https://api.portmodels.com/openai/v1/models/model-owner/example-model \
-H "Authorization: Bearer $PORTMODELS_API_KEY"Model keys often contain a slash. The path accepts it directly, so no encoding is needed here.
Choosing a model#
- Don't hard-code a single model forever. The catalogue changes; read the list at startup and fall back gracefully.
- Match the model to the job. Most app work does not need the largest model available, and the price difference is large. See Pricing and markup.
- Test cost, not just quality. Run the same realistic prompt through two
candidates and compare
usage.cost.
Model-specific usage#
The model catalog can change, so discover the current keys with
GET /openai/v1/models. The following sections show the request shape for the
currently published chat, image, and video models. A catalog entry does not
mean every model uses the same endpoint: video jobs use the action API below.
DeepSeek V4.1 Flash#
Use the exact model key deepseek-v4.1-flash with the chat completions
endpoint. It accepts normal text prompts and structured JSON requests:
curl https://api.portmodels.com/openai/v1/chat/completions \
-H "Authorization: Bearer $PORTMODELS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek-v4.1-flash",
"messages": [
{"role": "system", "content": "Return a concise answer."},
{"role": "user", "content": "List three uses for a product brief."}
],
"temperature": 0.2,
"max_tokens": 300
}'For JSON output, set response_format and state the expected JSON shape in
the messages:
{
"model": "deepseek-v4.1-flash",
"messages": [
{"role": "system", "content": "Return JSON with a string field named summary."},
{"role": "user", "content": "Summarize this text: ..."}
],
"response_format": {"type": "json_object"}
}Pruna p-image#
Use p-image with image generations. Ask for b64_json when your application
wants image bytes directly; otherwise the response may contain a hosted url.
curl https://api.portmodels.com/openai/v1/images/generations \
-H "Authorization: Bearer $PORTMODELS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "p-image",
"prompt": "A small blue ceramic cup on a white table, soft studio lighting",
"n": 1,
"size": "1024x1024",
"response_format": "b64_json"
}'Read the generated image from data[0].b64_json and the metered amount from
usage.cost. See Image generation for response handling
and storage guidance.
For p-image, an explicit size must use WIDTHxHEIGHT with each dimension
from 256 to 1440 pixels, in multiples of 16. 1024x1024 and 1440x816 are
valid examples; 1792x1024 is not. The API does not resize an unsupported
request automatically.
Pruna pruna-ai/p-image-edit#
Use pruna-ai/p-image-edit with the multipart image-edit endpoint. Upload the
source image in the image field and describe only the change you want:
curl https://api.portmodels.com/openai/v1/images/edits \
-H "Authorization: Bearer $PORTMODELS_API_KEY" \
-F "model=pruna-ai/p-image-edit" \
-F "prompt=Remove the sign in the background and fill the wall naturally" \
-F "[email protected];type=image/png" \
-F "size=1024x1024" \
-F "response_format=b64_json"For pruna-ai/p-image-edit, choose exactly one of these size values:
| Frame | size |
|---|---|
| Square | 1024x1024 |
| Landscape 4:3 | 1184x896 |
| Portrait 3:4 | 896x1184 |
| Widescreen | 1376x768 |
| Tall widescreen | 768x1376 |
| Landscape 3:2 | 1248x832 |
| Portrait 2:3 | 832x1248 |
1792x1024 is not supported. For a wide edit, send size=1376x768.
For a model supporting multi-image uploads, repeat the upload as image[].
Input formats, output sizes, and image counts are model-specific; unsupported
requests are rejected rather than silently converted to generation. The
response uses the same data and usage.cost shape as image generation. See
Image generation and editing for the multipart contract.
Grok Video 1.5: text, first-frame and reference images#
Use x-ai/grok-video-1.5 with ai.media.create at POST /run and a Connect
token with models.run, an API key with video permission, or an account token.
For first-frame generation, supply a public image URL in inputs.image; the tested request uses
video_generation_mode: "first_frame_image_to_video", one second, and 480p.
For reference generation, send inputs.reference_images and
video_generation_mode: "reference_images_to_video". For text-only generation,
use inputs: {} and video_generation_mode: "text_to_video".
Poll with ai.media.get, then read the MP4 URL from job.result[0].url and the
final charge from job.billing.settled_credits.
See Image-to-video for the complete authenticated example,
credit reservation behavior, and troubleshooting. This flow is not available
through /openai/v1/videos or the chat completions endpoint.
Seedance 1.0 Pro Fast: image-to-video#
Use bytedance/seedance-1.0-pro-fast with the same job API, placing source
image URLs in inputs.image_urls. The low-cost configuration uses two
seconds and 480p. See
Seedance image-to-video
for the complete request. Input field names differ between models.
Veo 3.1 Lite: text-to-video#
Use google/veo-3.1-lite with the same job API for the verified eight-second,
720p text-to-video configuration. Its parameters differ from Grok's; see
Other video models.
Allowed models for published apps#
A published app has an allowed_models list. When your app runs models with a
Connect token, that list applies — a model
outside it is rejected even if it appears in /v1/models. Keep the list current
as you change which models your app uses.