Ultralytics YOLO27:
Build with Ultralytics Platform·Deploy and Monitor·Lesson 7/10
Lessonintermediate

Deploy and Call an Endpoint

Create a dedicated endpoint in one of 42 regions, size it for your traffic, and call it with a client that handles cold starts, 429s, and bad keys.

A free endpoint that scales to zero can take up to a minute to answer its first request, and a naive client turns that into a user-facing timeout. A leaked key keeps working even after you delete it. This lesson deploys your winning model, sizes the endpoint deliberately, and writes the small client that every production integration needs.

Outcome

You can deploy a model to a dedicated endpoint, choose between the free and a custom size from your traffic pattern, and call it with a client that retries cold starts and 429s and fails fast on real errors.

Fast Track
If you already know your way around, here's the short version.
  1. On the model's Deploy tab, click Deploy on the lowest-latency region.

  2. Start at the free 1 vCPU, 2 GiB size; go custom only for steady real-time traffic.

  3. Call /predict from your server with the deployment's bound key; retry 429 and timeouts with backoff.

  4. Ship new models with Replace model: the URL, region, and key stay the same.

Hands-on

Shared Inference or a Dedicated Endpoint#

Every model can already be called through Platform's shared inference API, which suits testing. Production traffic belongs on a dedicated endpoint:

Shared inferenceDedicated endpoint
ServiceShared across Platform usersOne model, single tenant
RegionsYour data region (US, EU, or AP)Any of 42 regions
Rate limit20 requests per minute per keyNo Platform limit on direct calls
Request sizeAbout 4.5 MB32 MB, up to 1 hour per request (video works)
AuthAny workspace API keyOnly the key bound to the deployment

Create and Size the Endpoint#

Open the model's Deploy tab. Your browser measures latency to all 42 regions (14 in the Americas, 13 in Europe, 12 in Asia-Pacific, 3 in the Middle East and Africa) and sorts the table by it:

Ultralytics Platform model Deploy tab with a world map of region pins and a Region Latency table sorted by measured latency, each row with a Deploy button

Click Deploy on the row closest to your callers, review CPU, memory, price, and the generated name (such as yolo26n-iowa), and click Create Deployment. You can also start from New Deployment on your profile's Deployments tab:

Ultralytics Platform New Deployment dialog with a model selector, a region mini map with a latency table, and CPU set to 1 vCPU and memory to 2 GiB

Size by traffic pattern:

TrafficSizeCost
Batch jobs, internal tools, bursty demosDefault 1 vCPU, 2 GiB; scales to zeroFree on every plan
Steady real-time traffic that can't wait for a cold startCustom size (1–8 vCPU, 2–32 GiB) with one warm instanceBilled hourly from ready until stopped, idle included: about $0.12/h for 1 vCPU, 4 GiB in Iowa
Users on several continentsOne endpoint per region behind your own routerEach endpoint billed by its size

Ultralytics Platform New Deployment dialog with a region latency table and CPU and memory selectors set to a custom 1 vCPU and 4 GiB size

Plans allow 3 (Free), 10 (Pro), or unlimited (Enterprise) deployments, and stopped endpoints still count. The endpoint accepts traffic once its badge reads Ready:

Worked Example: A Client That Survives Production#

Ultralytics Platform deployment page for exp-3-los-angeles with request, error rate, and P95 latency cards, a location map, the Endpoint card with the copyable endpoint URL, and Deployment Information with pricing

Each endpoint has a URL like https://predict-<id>-<hash>-<region>.a.run.app serving /predict (POST), /health, and an interactive /docs page. It accepts only the API key bound at creation; workspace owners see that key pre-filled in the deployment's Predict tab under Docs, next to Python, JavaScript, and cURL snippets. The snippets make one request; production code must also survive a cold start and a busy instance:

import os
import time
from collections import Counter

import httpx

URL = "https://YOUR_DEPLOYMENT_URL.run.app/predict"
HEADERS = {"Authorization": f"Bearer {os.environ['ULTRALYTICS_API_KEY']}"}  # the deployment's bound key, server-side only

def predict(client, path, conf=0.25, attempts=4):
    """POST one image; retry timeouts, 429, and 5xx with backoff; fail fast on other errors."""
    for attempt in range(attempts):
        try:
            with open(path, "rb") as f:
                r = client.post(URL, headers=HEADERS, data={"conf": conf}, files={"file": f}, timeout=90)
            if r.status_code < 400:
                return r.json()
            if r.status_code != 429 and r.status_code < 500:
                r.raise_for_status()  # 401 wrong key, 413 too large: retrying won't help
            wait, reason = float(r.headers.get("Retry-After", 2**attempt)), r.status_code
        except httpx.TimeoutException:  # a scaled-to-zero endpoint can take up to a minute to wake
            wait, reason = 2**attempt, "timeout"
        print(f"attempt {attempt + 1}: {reason}, retrying in {wait:.0f} s")
        time.sleep(wait)
    raise RuntimeError(f"endpoint still unavailable after {attempts} attempts")

with httpx.Client() as client:
    response = predict(client, "bus.jpg")
for image in response["images"]:
    counts = Counter(d["name"] for d in image["results"])
    print(f"{sum(counts.values())} objects {dict(counts)} in {image['speed']['inference']:.1f} ms")

We tested it against a local stub that answers 429 once and then returns a real YOLO26n result for bus.jpg in the endpoint's response format:

attempt 1: 429, retrying in 2 s
5 objects {'bus': 1, 'person': 4} in 34.9 ms

Line by line, the decisions that matter:

  • timeout=90 covers a cold start of up to about a minute; the default timeouts of most HTTP clients are far shorter.
  • 429 and 5xx are retried, honoring Retry-After when the endpoint sends it. Each endpoint serves from a single instance and sheds load with 429 when busy.
  • Other 4xx errors fail fast: 401 means the wrong key and 413 a body over 32 MB, and neither fixes itself.
  • The response holds one entry per image (or per video frame) in images, each with results (class, name, confidence, box with x1, y1, x2, y2) and speed in milliseconds.

Optional form fields are conf (default 0.25), iou (0.7), imgsz (the model's training size), vid_stride for video, and normalize=true for 0–1 coordinates. The cURL equivalent is one line per field:

curl -X POST "https://YOUR_DEPLOYMENT_URL.run.app/predict" \
  -H "Authorization: Bearer $ULTRALYTICS_API_KEY" \
  -F "file=@bus.jpg" -F "conf=0.25" -F "iou=0.7" -F "imgsz=640"

Ship New Versions Without Changing the URL#

Replace model on the deployment page swaps in another completed model from the same workspace. The old model keeps serving until the new one is ready, the URL, region, and key stay the same, and if the rollout fails the previous model stays live. Rolling back is the same action pointed at the previous model, so keep it in the project. Update configuration resizes in place, and Stop pauses billing and keeps the URL.

Some changes need a new endpoint: regions are fixed (moving means delete and recreate, with a new URL), and custom domains aren't supported, so put your own gateway in front if callers need a stable branded hostname. To run outside Platform, export the model (Export for Deployment) or self-host it behind Triton Inference Server.

Pitfalls#

The API key ships to the browser

Symptom: your endpoint gets traffic you can't account for. Fix: never put the key in a web or mobile app; call the endpoint from your backend. Deleting or deactivating the bound key does not lock the endpoint, because it still accepts that key string. To revoke access, stop or delete the deployment, and create a new one bound to a fresh key.

First request after a quiet night times out

Symptom: the first morning request fails, and the retry succeeds. Fix: default-size endpoints scale to zero. Use a timeout of at least 90 seconds, warm the endpoint with a /health call before expected traffic, or switch to a custom size if every request must be fast.

Large videos are rejected

Symptom: uploads fail with 413. Fix: dedicated endpoints accept request bodies up to 32 MB. Split long videos into shorter clips or send sampled frames, and pass vid_stride to skip frames server-side.

Try It

Deploy your winning model at the default size in the lowest-latency region. Call it with client.py from a server or your terminal, then time one request after the endpoint has been idle for an hour (without opening its page) and one right after. Finally, replace the model with your runner-up and confirm the same URL answers with the new model's results.

Done When
You've finished the lesson when all of these are true.
  • client.py prints object counts from your endpoint.

  • You've measured a cold and a warm request and written down your sizing decision with its monthly cost.

  • A model replacement completed, and the same URL served the new model.

Show solution

Example answer for the pill line camera: deploy v2-finetune to europe-west1 (St. Ghislain, the lowest latency from the German plant) at the default size. Cold request after an idle hour: 38 s, which the 90-second timeout absorbs; warm request: 0.3 s. Decision: the line PLC sends a frame every 30 seconds during shifts, so the endpoint stays warm all shift and only the first frame pays a cold start. A /health call from the line controller 2 minutes before each shift removes that too, so the free default size stays, saving about $90 a month over a custom 1 vCPU, 4 GiB instance. Replace model back to v1-baseline returns v1's results from the same URL; replace again with v2 to finish.

What's next

You're live. Next you'll build the two checks that tell you when the endpoint or the model goes wrong.