Sign in Get started

Annotations

Read, save, and delete annotations on individual images. Save is a full overwrite — pass the complete list every time.

View as Markdown

Annotations follow the canonical Pictograph JSON schema — see Annotation format for the full spec.

The class label field is name (not class). Polygons use multi-ring paths, not flat coordinate arrays.

from pictograph import Client
client = Client()

get

Fetch the typed annotation list attached to an image.

annotations = client.annotations.get("img-uuid-1")
for ann in annotations:
    print(ann.name, ann.type)

Returns list[Annotation] — a discriminated union over BBoxAnnotation / PolygonAnnotation / PolylineAnnotation / KeypointAnnotation. An image with no annotations returns [] (never raises for the “no annotations” case — only for “no such image”).

save

Replace the image’s annotations with the supplied list. Full overwrite — existing annotations are dropped.

from pictograph import BBoxAnnotation, BoundingBox, PolygonAnnotation, PolygonGeometry, Point

result = client.annotations.save("img-uuid-1", [
    BBoxAnnotation(
        id="ann-1",
        name="person",
        bounding_box=BoundingBox(x=100, y=200, w=50, h=80),
    ),
    PolygonAnnotation(
        id="ann-2",
        name="car",
        polygon=PolygonGeometry(paths=[
            [Point(x=0, y=0), Point(x=10, y=0), Point(x=10, y=10)],
        ]),
    ),
])
print(result.previous_count, "→", result.new_count, result.status)
ArgTypeNotes
image_idstrImage UUID
annotationsSequence[Annotation]Pydantic-validated client-side; backend re-validates

Returns SaveResultimage_id, previous_count, new_count, status ("new" / "in_progress" / "complete", set automatically by count).

Polygons may omit bounding_box on save — the backend computes the enclosing rectangle server-side.

delete

Remove every annotation from the image. Equivalent to save(image_id, []) but uses DELETE and requires admin+ role.

result = client.annotations.delete("img-uuid-1")
print(result.deleted_count)

Validation

The SDK Pydantic models reject malformed payloads at construction:

from pictograph import PolygonAnnotation, PolygonGeometry, Point

PolygonGeometry(paths=[[Point(x=0, y=0)]])
# ValidationError: paths[0] has 1 point(s); polygon ring requires >= 3

The backend re-validates on save as defense-in-depth — agents that construct dicts directly will hit 422 ValidationError for the same class of mistakes.

Common errors

StatusExceptionCause
404NotFoundErrorimage_id doesn’t exist
422ValidationErrorclass instead of name, flat polygon array, unknown class label
403ForbiddenErrordelete requires admin+ role

Auto-annotate workflow

If you want SAM3 to generate annotations rather than write them by hand, see the auto-annotate resource. The auto_annotate_dataset workflow saves annotations automatically; the single-prompt methods return a PromptResult and you call save yourself.

REST equivalent

curl -X POST -H "X-API-Key: pk_live_…" \
     -H "Content-Type: application/json" \
     -d '{"image_id":"…","annotations":[…]}' \
     https://api.pictograph.io/api/v1/developer/annotations/<image_id>
Copied to clipboard