---
title: "Link Callout"
method: POST
path: "/api/v1/parts/{part_id}/drawings/link-callout"
tags: ["drawings"]
---

# Link Callout

`POST /api/v1/parts/{part_id}/drawings/link-callout`

Manually link (or unlink) a drawing callout to a 3D feature.

This persists the link in two places:

1. **Immediate:** mutates ``part.drawing_analysis[category][idx].feature_id``
   in place so the frontend sees the link reflected on the next query.
   Uses ``flag_modified`` because SQLAlchemy's MutableDict does not
   recursively track nested mutations (see comment on Part.drawing_analysis).
2. **Durable:** creates an ``OutcomeEvent`` with
   ``outcome_type="user_drawing_link"`` so the stitcher respects the
   user's choice on re-run (and we have an audit trail).

Validates:
- User owns the parent project (404 otherwise)
- Category is one of the valid drawing_analysis field names (400 otherwise)
- callout_index is within bounds (400 otherwise)
- When action='link', target_feature_id is provided AND exists on a
  detected feature in the part's latest CAD version (400 otherwise)

## Path parameters

- `part_id` string, uuid, required

## Request body

- LinkCalloutRequest — Manually link (or unlink) a drawing callout to a 3D feature. Used by the "unmatched callouts hopper" UI — when the user drags a callout that the LLM stitcher couldn't auto-match onto a 3D feature, the frontend POSTs this to persist the manual link as both: 1. An OutcomeEvent with ``outcome_type="user_drawing_link"`` for audit + stitcher re-run respect 2. An in-place update to ``part.drawing_analysis[category][idx].feature_id`` for immediate UI reflection
  - `category` string, required — Drawing callout category: tolerances, gd_and_t, surface_finish, threads, bores, chamfers, radii
  - `callout_index` integer, required — Zero-based index into drawing_analysis[category]
  - `target_feature_id` string, nullable — The 3D feature_id to link this callout to. Required when action='link'. Ignored when action='unlink'.
  - `action` string, required — 'link' or 'unlink'

## Response `200`

Successful Response

- LinkCalloutResponse — Response after linking/unlinking a callout. Returns the updated drawing_analysis blob so the frontend can refresh its local state without a separate fetch.
  - `drawing_analysis` object, required — Updated drawing_analysis after the link/unlink

## Other responses

- `422` — Validation Error

---

[API](https://skmtc.dev/prototyping/apis/prototyping-io-api.md) · [All operations](https://skmtc.dev/prototyping/apis/prototyping-io-api/llms.txt) · [OpenAPI document](https://skmtc.dev/prototyping/apis/prototyping-io-api/revisions/f4a0079fbb57?raw)
