Sign in Get started

Deployments API

Stand a trained model up as an always-on inference endpoint, billed by uptime, and call it directly.

View as Markdown

A deployment turns a trained model into a live /predict endpoint you call over HTTP. Each deployment is its own isolated app with one authenticated URL. Billing is by uptime, so you pause a deployment to stop charges and resume it to bring the endpoint back.

Two credentials, deliberately separate. Managing deployments uses your normal X-API-Key. Calling a deployment’s /predict endpoint uses a per-deployment bearer token (prefix pk_deploy_), which create returns. See Calling your deployment.

Deployments run on every plan, Free included, billed by uptime from your compute credits. For batch inference over a dataset or video, use the Workflows API instead: a workflow loads the model per run and needs no standing deployment.

Deployments are addressed by name on all three surfaces; a UUID works anywhere a name does.

Compute types

A deployment runs on one compute tier. min_containers=0 is scale-to-zero: you are billed only while the endpoint is serving, with a short cold start on the first request after idle. min_containers>=1 keeps that many containers warm, for lowest latency and continuous billing.

compute_type gpu_type Notes
gpu (default) t4 (default), l4, a10g, a100 Pick the smallest tier your model fits
cpu not applicable CPU-only inference for light models

compute_options

The selectable tiers with their per-minute rate in micro-USD. Use it to populate a picker before quoting or creating.

Source: Deployments.compute_options

for option in client.deployments.compute_options():
    print(option.label, option.compute_type, option.gpu_type, option.rate_per_min_micro_usd)
pictograph deployments compute-options
curl -s "https://api.pictograph.io/api/v1/developer/deployments/compute-options" \
  -H "X-API-Key: $PICTOGRAPH_API_KEY"

Returns Sequence[DeploymentComputeOption]

DeploymentComputeOption · 7 fields
class DeploymentComputeOption(BaseModel):
    """A selectable deployment compute tier + its per-minute rate (one warm container)."""
    key: str
    label: str
    compute_type: Literal['cpu', 'gpu']
    gpu_type: Optional[Literal['t4', 'l4', 'a10g', 'a100']] = None
    is_gpu: bool
    description: str = ''
    rate_per_min_micro_usd: int

quote

Cost quote for a tier before you create. The args mirror create, so you can quote and then create with the same values.

Source: Deployments.quote

Arg Type Default Notes
compute_type ComputeType "gpu" "gpu" or "cpu"
gpu_type DeploymentGpuType | None None Required when compute_type="gpu"
min_containers int 0 0 quotes scale-to-zero; >=1 quotes always-warm
quote = client.deployments.quote(
    compute_type="gpu",
    gpu_type="t4",
    min_containers=0,
)
print(quote.rate_per_min_micro_usd, quote.cost_per_hour_micro_usd, quote.billing_note)
pictograph deployments quote --compute-type gpu --gpu t4 --min-containers 0
curl -s "https://api.pictograph.io/api/v1/developer/deployments/quote?compute_type=gpu&gpu_type=t4&min_containers=0" \
  -H "X-API-Key: $PICTOGRAPH_API_KEY"

Returns DeploymentQuote

DeploymentQuote · 5 fields
class DeploymentQuote(BaseModel):
    """Cost quote for a deployment, before creating it. All amounts are already-marked-up micro-USD (1 USD = 1_000_000 µUSD)."""
    rate_per_min_micro_usd: int
    cost_per_hour_micro_usd: int
    cost_per_day_micro_usd: int
    scale_to_zero: bool
    billing_note: str

create

Deploy a trained model to a live endpoint. The response carries the plaintext bearer token (prefix pk_deploy_). Store it now: the API never returns it again (a member can reveal it from the deployment’s settings in the app, once a session). The deployment starts in provisioning; poll get until status is active and endpoint_url is set, then call it.

Source: Deployments.create

Arg Type Default Notes
model str required Trained model by name; status must be ready
name str | None None Unique within your organization; auto-generated if omitted
compute_type ComputeType "gpu" "gpu" or "cpu"
gpu_type DeploymentGpuType | None "t4" Ignored for compute_type="cpu"
min_containers int 0 0 is scale-to-zero; >=1 keeps warm (max 5)
max_containers int 1 Autoscale ceiling (max 10)
scaledown_window int 60 Seconds a container stays warm after the last request
inference_config dict | None None Per-model defaults, e.g. a confidence threshold
created = client.deployments.create(
    model="Swift Falcon",
    name="prod-detector",
    compute_type="gpu",
    gpu_type="t4",
    min_containers=0,
    max_containers=2,
    scaledown_window=60,
)
print(created.deployment.id, created.deployment.status)
print(created.auth_token)   # pk_deploy_... - store it now
pictograph deployments create "Swift Falcon" \
  --name prod-detector --gpu t4 --min 0 --max 2 --scaledown 60
# REST takes the model's UUID; the SDK and CLI resolve the name for you.
curl -s -X POST "https://api.pictograph.io/api/v1/developer/deployments/" \
  -H "X-API-Key: $PICTOGRAPH_API_KEY" -H "Content-Type: application/json" \
  -d '{"model_id": "<model-uuid>", "name": "prod-detector", "compute_type": "gpu", "gpu_type": "t4", "min_containers": 0, "max_containers": 2, "scaledown_window": 60}'

Returns CreatedDeployment

CreatedDeployment · 2 fields
class CreatedDeployment(BaseModel):
    """Create response - carries the one-time plaintext bearer token."""
    deployment: Deployment
    auth_token: str

get

Fetch one deployment. Poll this after create until status is active.

Source: Deployments.get

Arg Type Default Notes
deployment str required Deployment name or id.
deployment = client.deployments.get(
    deployment="prod-detector",
)
print(deployment.status, deployment.endpoint_url)
pictograph deployments get prod-detector
curl -s "https://api.pictograph.io/api/v1/developer/deployments/prod-detector" \
  -H "X-API-Key: $PICTOGRAPH_API_KEY"

Returns Deployment

Deployment · 19 fields
class Deployment(BaseModel):
    """A live (or provisioning) model inference deployment."""
    id: str
    organization_id: str
    model_id: str
    name: str
    status: Literal['provisioning', 'active', 'paused', 'failed', 'terminated']
    compute_type: Literal['cpu', 'gpu']
    gpu_type: Optional[Literal['t4', 'l4', 'a10g', 'a100']] = None
    min_containers: int
    max_containers: int
    scaledown_window: int
    endpoint_url: str | None = None
    auth_token_prefix: str | None = None
    inference_config: dict[str, Any] = {}
    cost_rate_per_min: int = 0
    cost_per_hour: int | None = None
    accrued_cost_credits: int = 0
    uptime_seconds: int = 0
    created_at: datetime | None = None
    started_at: datetime | None = None

A cross-organization or missing name is a 404.

list

One page of deployments, optionally filtered by model or status.

Source: Deployments.list

Arg Type Default Notes
model str | None None Restrict to deployments of one model, by name
status DeploymentStatus | None None provisioning / active / paused / failed / terminated
limit int 50 Page size
offset int 0 Page offset
for deployment in client.deployments.list(status="active", limit=50):
    print(deployment.name, deployment.status, deployment.endpoint_url)
pictograph deployments list --status active --limit 50
curl -s "https://api.pictograph.io/api/v1/developer/deployments/?status=active&limit=50" \
  -H "X-API-Key: $PICTOGRAPH_API_KEY"

Returns list[Deployment]

Deployment · 19 fields
class Deployment(BaseModel):
    """A live (or provisioning) model inference deployment."""
    id: str
    organization_id: str
    model_id: str
    name: str
    status: Literal['provisioning', 'active', 'paused', 'failed', 'terminated']
    compute_type: Literal['cpu', 'gpu']
    gpu_type: Optional[Literal['t4', 'l4', 'a10g', 'a100']] = None
    min_containers: int
    max_containers: int
    scaledown_window: int
    endpoint_url: str | None = None
    auth_token_prefix: str | None = None
    inference_config: dict[str, Any] = {}
    cost_rate_per_min: int = 0
    cost_per_hour: int | None = None
    accrued_cost_credits: int = 0
    uptime_seconds: int = 0
    created_at: datetime | None = None
    started_at: datetime | None = None

iter

Auto-paging iterator over every deployment. The CLI and REST surfaces page manually.

Source: Deployments.iter

Arg Type Default Notes
model str | None None Model name or id.
name str | None None Only deployments whose name matches.
status DeploymentStatus | None None Only deployments in this state: provisioning, active, paused, failed or terminated.
page_size int 50 Rows fetched per underlying request. Tuning only - the iterator yields every item either way.
max_total int | None None Stop after this many items. None walks everything.
for deployment in client.deployments.iter(page_size=50):
    print(deployment.name, deployment.status)
curl -s "https://api.pictograph.io/api/v1/developer/deployments/?limit=50&offset=0" \
  -H "X-API-Key: $PICTOGRAPH_API_KEY"
# The CLI does not auto-page; this is a single page.
pictograph deployments list

Returns OffsetPager[Deployment]

Deployment · 19 fields
class Deployment(BaseModel):
    """A live (or provisioning) model inference deployment."""
    id: str
    organization_id: str
    model_id: str
    name: str
    status: Literal['provisioning', 'active', 'paused', 'failed', 'terminated']
    compute_type: Literal['cpu', 'gpu']
    gpu_type: Optional[Literal['t4', 'l4', 'a10g', 'a100']] = None
    min_containers: int
    max_containers: int
    scaledown_window: int
    endpoint_url: str | None = None
    auth_token_prefix: str | None = None
    inference_config: dict[str, Any] = {}
    cost_rate_per_min: int = 0
    cost_per_hour: int | None = None
    accrued_cost_credits: int = 0
    uptime_seconds: int = 0
    created_at: datetime | None = None
    started_at: datetime | None = None

Calling your deployment

Once a deployment is active, call its endpoint_url (it already ends in /predict) with the pk_deploy_ token from create. This request uses the per-deployment bearer token, not your X-API-Key.

Source: DeploymentClient

infer arg Type Default Notes
image str | bytes | Path required Local path, an http(s):// URL, or raw bytes
confidence float | None None Override the deployment’s default threshold
class_filter list[str] | None None Restrict the returned classes
top_k int | None None Classifiers: how many predictions to return
from pictograph import Client, DetectionResult

client = Client()
deployment = client.deployments.get(
    deployment="prod-detector",
)

# `task=` narrows the result type, exactly as it does on get_model.
infer = client.deployments.connect(
    deployment=deployment,
    api_key="pk_deploy_...",
    task="object_detection",
)

result: DetectionResult = infer.infer("photo.jpg", confidence=0.4)
for prediction in result.predictions:
    print(prediction.name, round(prediction.confidence, 2), prediction.bounding_box)

# infer_raw(...) returns the endpoint's JSON untouched.
# --endpoint makes the pk_deploy_ token the only credential needed.
pictograph deployments predict prod-detector photo.jpg \
  --token "pk_deploy_..." --confidence 0.4
# A local file as multipart:
curl -s -X POST "$ENDPOINT_URL" \
  -H "Authorization: Bearer pk_deploy_..." \
  -F "file=@photo.jpg"

# Or a URL / base64 image as JSON, with options inline:
curl -s -X POST "$ENDPOINT_URL" \
  -H "Authorization: Bearer pk_deploy_..." -H "Content-Type: application/json" \
  -d '{"image": {"type": "url", "value": "https://example.com/photo.jpg"}, "confidence": 0.4}'

$ENDPOINT_URL is the deployment’s endpoint_url. The response is the model’s JSON, shaped {"predictions": [...], ...}.

With the URL in hand the token is the only credential you need, no account API key: DeploymentClient(endpoint_url, "pk_deploy_...", task="object_detection") in Python, or --endpoint <url> --token <token> on the CLI.

bulk_delete

Terminate many deployments and tear down their endpoints. One request the backend resolves per item, rather than N separate calls. Idempotent: duplicates collapse, and any name that does not resolve is reported in not_found rather than raising.

Source: Deployments.bulk_delete

Arg Type Default Notes
deployments Sequence[str] required Deployment names or ids to act on. Names that do not resolve are reported, not raised.
result = client.deployments.bulk_delete(
    deployments=["prod-detector", "staging-detector"],
)
print(result.count, "changed;", result.not_found, "not found")
# No bulk command - run the per-deployment one over your list.
pictograph deployments delete prod-detector
pictograph deployments delete staging-detector
curl -s -X POST "https://api.pictograph.io/api/v1/developer/deployments/bulk-delete" \
  -H "X-API-Key: $PICTOGRAPH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"deployment_ids": ["$PROD_ID", "$STAGING_ID"]}'

Returns BulkDeleteResult

BulkDeleteResult · 3 fields
class BulkDeleteResult(BaseModel):
    """Result of a server-side bulk delete (one chunked, org-scoped call)."""
    succeeded: list[str] = []
    not_found: list[str] = []
    count: int = 0

bulk_pause

Pause many deployments, stopping uptime billing on each. One request the backend resolves per item, rather than N separate calls. Idempotent: duplicates collapse, and any name that does not resolve is reported in not_found rather than raising.

Source: Deployments.bulk_pause

Arg Type Default Notes
deployments Sequence[str] required Deployment names or ids to act on. Names that do not resolve are reported, not raised.
result = client.deployments.bulk_pause(
    deployments=["prod-detector", "staging-detector"],
)
print(result.count, "changed;", result.not_found, "not found")
# No bulk command - run the per-deployment one over your list.
pictograph deployments pause prod-detector
pictograph deployments pause staging-detector
curl -s -X POST "https://api.pictograph.io/api/v1/developer/deployments/bulk-pause" \
  -H "X-API-Key: $PICTOGRAPH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"deployment_ids": ["$PROD_ID", "$STAGING_ID"]}'

Returns BulkActionResult

BulkActionResult · 3 fields
class BulkActionResult(BaseModel):
    """Result of a server-side bulk state-change (e.g. pause/resume)."""
    succeeded: list[str] = []
    not_found: list[str] = []
    count: int = 0

bulk_resume

Resume many paused deployments, re-provisioning each. One request the backend resolves per item, rather than N separate calls. Idempotent: duplicates collapse, and any name that does not resolve is reported in not_found rather than raising.

Source: Deployments.bulk_resume

Arg Type Default Notes
deployments Sequence[str] required Deployment names or ids to act on. Names that do not resolve are reported, not raised.
result = client.deployments.bulk_resume(
    deployments=["prod-detector", "staging-detector"],
)
print(result.count, "changed;", result.not_found, "not found")
# No bulk command - run the per-deployment one over your list.
pictograph deployments resume prod-detector
pictograph deployments resume staging-detector
curl -s -X POST "https://api.pictograph.io/api/v1/developer/deployments/bulk-resume" \
  -H "X-API-Key: $PICTOGRAPH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"deployment_ids": ["$PROD_ID", "$STAGING_ID"]}'

Returns BulkActionResult

BulkActionResult · 3 fields
class BulkActionResult(BaseModel):
    """Result of a server-side bulk state-change (e.g. pause/resume)."""
    succeeded: list[str] = []
    not_found: list[str] = []
    count: int = 0

connect

Build a DeploymentClient bound to one active deployment. It calls the deployment’s own /predict URL with the pk_deploy_ bearer token, so it needs no account API key - see Calling your deployment.

Source: Deployments.connect

Arg Type Default Notes
deployment Deployment required An active deployment, as returned by get or create.
api_key str required The deployment’s own pk_deploy_ token, from create (or revealed in the app).
task TaskName | None None Narrows the returned result type. None reads the task from the deployment.
timeout float 60.0 Seconds to wait for a single prediction.
deployment = client.deployments.get(
    deployment="prod-detector",
)
endpoint = client.deployments.connect(
    deployment=deployment,
    api_key="pk_deploy_...",
    task="object_detection",
)
result = endpoint.infer("photo.jpg", confidence=0.4)
# No `connect` command - it returns an SDK object, not a request. The CLI
# reaches the same endpoint directly:
pictograph deployments predict prod-detector ./photo.jpg --token pk_deploy_...
# `connect` builds a client locally and issues no request of its own. What it
# then calls is the deployment's endpoint:
curl -s -X POST "$ENDPOINT_URL" \
  -H "Authorization: Bearer pk_deploy_..." \
  -F "file=@photo.jpg"

Returns DeploymentClient[Any]

A typed client. infer(...) returns the parsed result for the task; infer_raw(...) returns the endpoint’s JSON untouched.

delete

Terminate a deployment and tear down its serving endpoint. Uptime billing stops and the pk_deploy_ token is invalidated. This is not reversible - create a new deployment to serve the model again.

Source: Deployments.delete

Arg Type Default Notes
deployment str required Deployment name or id.
client.deployments.delete(
    deployment="prod-detector",
)
pictograph deployments delete prod-detector --yes
# REST takes the deployment's id; the SDK and CLI resolve the name for you.
curl -s -X DELETE "https://api.pictograph.io/api/v1/developer/deployments/$DEPLOYMENT_ID" \
  -H "X-API-Key: $PICTOGRAPH_API_KEY"

Returns None

pause

Pause a deployment by NAME (stops compute + billing). An id works too.

Source: Deployments.pause

Arg Type Default Notes
deployment str required Deployment name or id.
deployment = client.deployments.pause(
    deployment="prod-detector",
)
print(deployment.status)   # paused - uptime billing stops here
pictograph deployments pause signs-detector
curl -s -X POST "https://api.pictograph.io/api/v1/developer/deployments/my-deployment/pause" \
  -H "X-API-Key: $PICTOGRAPH_API_KEY"

Returns Deployment

Deployment · 19 fields
class Deployment(BaseModel):
    """A live (or provisioning) model inference deployment."""
    id: str
    organization_id: str
    model_id: str
    name: str
    status: Literal['provisioning', 'active', 'paused', 'failed', 'terminated']
    compute_type: Literal['cpu', 'gpu']
    gpu_type: Optional[Literal['t4', 'l4', 'a10g', 'a100']] = None
    min_containers: int
    max_containers: int
    scaledown_window: int
    endpoint_url: str | None = None
    auth_token_prefix: str | None = None
    inference_config: dict[str, Any] = {}
    cost_rate_per_min: int = 0
    cost_per_hour: int | None = None
    accrued_cost_credits: int = 0
    uptime_seconds: int = 0
    created_at: datetime | None = None
    started_at: datetime | None = None

resume

Resume a paused deployment by NAME (re-provisions the endpoint).

Source: Deployments.resume

Arg Type Default Notes
deployment str required Deployment name or id.
deployment = client.deployments.resume(
    deployment="prod-detector",
)
print(deployment.status, deployment.endpoint_url)
pictograph deployments resume signs-detector
curl -s -X POST "https://api.pictograph.io/api/v1/developer/deployments/my-deployment/resume" \
  -H "X-API-Key: $PICTOGRAPH_API_KEY"

Returns Deployment

Deployment · 19 fields
class Deployment(BaseModel):
    """A live (or provisioning) model inference deployment."""
    id: str
    organization_id: str
    model_id: str
    name: str
    status: Literal['provisioning', 'active', 'paused', 'failed', 'terminated']
    compute_type: Literal['cpu', 'gpu']
    gpu_type: Optional[Literal['t4', 'l4', 'a10g', 'a100']] = None
    min_containers: int
    max_containers: int
    scaledown_window: int
    endpoint_url: str | None = None
    auth_token_prefix: str | None = None
    inference_config: dict[str, Any] = {}
    cost_rate_per_min: int = 0
    cost_per_hour: int | None = None
    accrued_cost_credits: int = 0
    uptime_seconds: int = 0
    created_at: datetime | None = None
    started_at: datetime | None = None

Common errors

Status Exception Cause
402 PaymentRequiredError Insufficient credits to provision or resume
403 ForbiddenError Role too low (delete needs admin+)
404 NotFoundError Deployment or model does not exist in your organization
409 ConflictError Duplicate name, or an action invalid for the current status
422 ValidationError Unknown gpu_type, or gpu_type missing for compute_type="gpu"
Copied to clipboard