Annotations
Read, save, and delete annotations on individual images. Save is a full overwrite — pass the complete list every time.
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)
| Arg | Type | Notes |
|---|---|---|
image_id | str | Image UUID |
annotations | Sequence[Annotation] | Pydantic-validated client-side; backend re-validates |
Returns SaveResult — image_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
| Status | Exception | Cause |
|---|---|---|
| 404 | NotFoundError | image_id doesn’t exist |
| 422 | ValidationError | class instead of name, flat polygon array, unknown class label |
| 403 | ForbiddenError | delete 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>