Record Placement (Materialized)
Method
This API follows the REST methodology.
HTTP Method
POST: Record that a wf2des Design Has Been Materialized
Naming Convention
To ensure consistency and readability, JSON nodes in requests and responses use camelCase. SQS payload nodes use snake_case.
Request and Response
Headers
Meta information is set in HTTP headers, not in the response body.
Request Headers
AuthorizationContent-TypeAcceptAccept-language
Response Headers
Content-Type
Record that a wf2des Design Has Been Materialized
URI
Path Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| organization_id | integer | Required | Organization ID |
| project_id | integer | Required | Project ID |
| wf2des_id | string | Required | wf2des ID |
Request Body
The request body is JSON. The Figma plugin, having already written the full materializer detail (placed_node_id, materializer_report) to the design_generation_result document's placement block through wf2des-api, calls this endpoint to flip the row-level materializedAt flag. The body carries only the node reference needed to echo the completion back to the caller; the load-bearing detail lives in the DocumentDB placement block, not on the PostgreSQL row.
Request Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| placedNodeId | string | Required | Figma node id of the frame the plugin built (mirrors placement.placed_node_id in DocumentDB) |
Response
The response is JSON (HTTP status: 200 OK).
{
"projectId": "proj-123",
"wf2desId": "wf2des-001",
"status": "1",
"phase": null,
"placedNodeId": "1204:57",
"materializedAt": "2026-07-06T09:35:00Z"
}
Response Fields
| Name | Type | Description |
|---|---|---|
| projectId | string | Project ID |
| wf2desId | string | wf2des ID |
| status | string | Run status โ always "1" (completed) for a materializable row (see Status Codes) |
| phase | string | null | Generation phase โ already cleared to null on a completed row |
| placedNodeId | string | Figma node id of the built frame (echo of the request) |
| materializedAt | string | ISO 8601 timestamp the row was flipped to materialized (materialized_at mirror) |
A repeated placement call on a row that already carries materializedAt returns 200 OK with the existing timestamp (idempotent โ the flag is not re-stamped). The placedNodeId in a repeat call is ignored for the row flip; the authoritative node reference is the one the plugin has already written to the DocumentDB placement block.
Status Codes
status:
| Value | Meaning |
|---|---|
0 |
processing |
1 |
completed |
2 |
failed |
3 |
rejected (designer declined the parse; NOT failed) |
4 |
cancelled |
Only a row at status "1" (completed) is materializable. phase is namespaced inside status "0" and is already null on any terminal row, including a completed one.
Authentication
Authentication is performed using JSON Web Tokens (JWT) issued by Amazon Cognito.
The Figma plugin calls this endpoint with an authenticated session that has Write access to the project. Recording placement is not restricted to the session that triggered the generation โ any Write session may confirm that the frame was built. This backend endpoint is distinct from the plugin's data-plane write to wf2des-api (which carries the plugin session token, not the Cognito JWT); the materializer detail reaches DocumentDB through that data-plane path first, and only this flag flip reaches the PostgreSQL row.
Error Handling
The following status codes are returned for errors.
| Description | Status Code | Status Name |
|---|---|---|
| Missing authentication credentials | 401 | Unauthorized |
| Insufficient permissions | 403 | Forbidden |
| wf2des, project, or organization not found | 404 | Not Found |
| Internal server error | 500 | Internal Server Error |
Processing Flow
The backend owns the wf2des PostgreSQL row and is the sole writer. Recording placement is a single flag update applied backend-side โ the worker holds no PostgreSQL credentials and never participates. This endpoint is the flag in a detail-first-then-flag handshake: the plugin first writes placed_node_id and the seven-event materializer report (name_fallback, ordinal_fallback, build_error, font_fallback, prop_rejected, unmatched, preserved) to DocumentDB, then calls this endpoint. The detail is durable before the flag is stamped.
- Extract organization ID, project ID, and wf2des_id from path parameters
- Extract
placedNodeIdfrom the request body - Verify the user has Write access to the project
- Fetch the
wf2desrow bywf2des_id; if it does not exist (or is soft-deleted), return 404 - Verify the row's
organization_idandproject_idmatch the path; otherwise return 404 - Inspect the current row:
status "1"(completed) withmaterializedAtalready set โ return 200 with the existing timestamp (idempotent, no write)status "1"(completed) withmaterializedAtunset โ proceed- Any non-completed
status("0"processing /"2"failed /"3"rejected /"4"cancelled) โ return 404 (no materializable result exists for this row) - Apply the update in one PostgreSQL transaction โ set
materialized_atto the current timestamp, stampupdated_at/updated_by;statusstays"1"andphasestaysnull - Return the materialized wf2des information
No SQS message is emitted by this endpoint. The generation is already terminal; this call only records that the client-side materialization step completed. It does not read or fetch the DesignSpec โ the DesignSpec is a native-Figma spec in the design_generation_result document (DocumentDB), fetched by the plugin through wf2des-api and materialized into the target Figma file; the backend never handles design content here.
Detailed Flowchart
flowchart TD
Start([POST Request]) --> Auth[Auth & Parameter Extraction]
Auth --> Service[Service Layer]
Service --> AccessCheck[Access Check]
AccessCheck --> HasAccess{Write Access?}
HasAccess -->|No| Err403[403 Forbidden]
HasAccess -->|Yes| FetchRow[Fetch wf2des Row<br/>WHERE id = :wf2des_id]
FetchRow --> RowExists{Exists &<br/>org/project match?}
RowExists -->|No| Err404[404 Not Found]
RowExists -->|Yes| StatusCheck{status '1'<br/>completed?}
StatusCheck -->|No โ '0' / '2' / '3' / '4'| Err404
StatusCheck -->|Yes| MatCheck{materializedAt<br/>already set?}
MatCheck -->|Yes| Idempotent[200 OK<br/>existing timestamp, no write]
MatCheck -->|No| Update[Update in one PG txn<br/>materialized_at = now<br/>status '1' / phase null unchanged]
Update --> Success[200 OK<br/>materialized wf2des info]
Detail-First-Then-Flag Handshake
Placement is recorded in two writes across two surfaces, in a fixed order:
- Detail (data plane, wf2des-api). The plugin writes
placed_node_id,materialized_at, fingerprint/review fields, and the seven-eventmaterializer_report. This write targets DocumentDB and never touches PostgreSQL.placement.design_arearemains worker-written. - Flag (this endpoint, backend). The plugin then calls
POST โฆ/wf2des/{wf2des_id}/placement, which flips the row-levelmaterializedAt. The flag is stamped last, so a setmaterializedAton thewf2desrow guarantees the fullerplacementdetail is already durable in DocumentDB.GETand list surfacematerializedAtfrom the row; the report itself is read from theplacementblock via wf2des-api.
This ordering keeps the row flag a reliable pointer: consumers polling GET see materializedAt only after the materializer detail has been committed, never before.