E104: Create transfer between locations
POST /api/finished-goods-inventory/transfers
Records the outbound leg of a finished goods transfer between two locations. Triggered from the Finished Goods Inventory Transfers page, "New transfer". The single outbound row encodes both source and destination; the inbound leg is added later via E105 when the receiving location confirms arrival.
Authentication
Standard tenant route. Requires Authorization: Bearer <firebase-id-token> and X-Org-Id: <org-id>. Access: Member. Also reachable with an org-scoped PAT.
Request
{
"skuId": "uuid",
"sourceLocationId": "uuid",
"destinationLocationId": "uuid",
"quantity": 100,
"eventDate": "2026-06-10T00:00:00Z",
"notes": "..."
}
quantity must be positive. eventDate and notes are optional. The ref is generated server-side as TFR-FG-<seq> (per-tenant); the endpoint writes a single TRANSFER row carrying to_location_id, and the matching RECEIVE row is written when E105 completes it.
Response — 201 Created
{
"ledgerEntry": {
"id": "uuid",
"orgId": "uuid",
"code": "FIL-001",
"skuId": "uuid",
"locationId": "uuid",
"eventType": "TRANSFER",
"quantity": "100",
"unitCost": null,
"ref": "TFR-FG-042",
"toLocationId": "uuid",
"notes": "...",
"eventDate": "2026-06-10T00:00:00Z",
"sourceType": null,
"sourceId": null,
"createdAt": "2026-06-10T00:00:00Z"
},
"ref": "TFR-FG-042"
}
locationId is the source; toLocationId is the destination. Numeric columns arrive as strings.
Errors
| HTTP | code | Condition |
|---|---|---|
| 404 | not_found | SKU, source, or destination location not found. |
| 422 | validation_failed | Source and destination are the same, quantity is not positive, or the SKU is inactive. |