Warehouses
A warehouse is a stock location: a physical address (or virtual bin) where inventory is held. Every variant stock level, stock movement, reservation, and outbound shipment hangs off a warehouse. The first warehouse you create is auto-flagged isDefault: true and used as the implicit source for movements that don't name one explicitly. See Concepts → Warehouse for the data model and Portal → Warehouses for the dashboard equivalent.
All requests on this page must be signed — see Authentication for the Fulkruma-HMAC-SHA256 recipe — and follow the response envelope described in the API overview.
Endpoints
| Method | Path | Purpose |
|---|---|---|
GET |
/api/v1/warehouses |
List warehouses |
POST |
/api/v1/warehouses |
Create a warehouse |
PATCH |
/api/v1/warehouses/:id |
Update a warehouse |
DELETE |
/api/v1/warehouses/:id |
Soft-archive a warehouse |
Retrieve-one is not currently exposed — list the resource and filter client-side. The list endpoint always returns the workspace's full set; warehouses are deliberately a low-cardinality resource (most merchants have one).
List warehouses
GET /api/v1/warehouses
Returns every non-archived warehouse in the workspace, ordered with the default first, then by createdAt ascending. Pagination is not supported and not needed — the page caps out at the workspace's warehouse count, which is plan-limited.
Response — 200 OK
{
"data": {
"warehouses": [
{
"id": "wh_01HXAB7K3M9N2P5QRS8TVWXY3Z",
"accountId": "acc_01HXxxxxxxxxxxxxxxxxxxxxxx",
"name": "Main warehouse",
"address": "Jl. Sudirman 123",
"city": "Jakarta",
"postal": "10220",
"lat": -6.2088,
"lng": 106.8456,
"phone": "+628111111111",
"isDefault": true,
"archived": false,
"createdAt": "2026-05-12T10:42:00.123Z",
"updatedAt": "2026-05-12T10:42:00.123Z"
}
]
},
"error": null,
"meta": {
"requestId": "req_01HX...",
"timestamp": "2026-05-12T10:42:00.124Z"
}
}
// Node
import { Fulkruma } from '@forjio/fulkruma';
const fk = new Fulkruma({ keyId: process.env.FULKRUMA_KEY_ID, secret: process.env.FULKRUMA_KEY_SECRET });
const { warehouses } = await fk.warehouses.list();
console.log(warehouses[0].id); // wh_...
# Python
from fulkruma import Fulkruma
fk = Fulkruma(key_id=os.environ['FULKRUMA_KEY_ID'], secret=os.environ['FULKRUMA_KEY_SECRET'])
warehouses = fk.warehouses.list()['warehouses']
// Go
import fulkruma "github.com/hachimi-cat/fulkruma-go"
client := fulkruma.New(os.Getenv("FULKRUMA_KEY_ID"), os.Getenv("FULKRUMA_KEY_SECRET"))
res, err := client.Warehouses.List(ctx)
# curl (assumes the fulkruma_curl helper from /docs/api/authentication)
fulkruma_curl GET '/api/v1/warehouses'
Create a warehouse
POST /api/v1/warehouses
Creates a warehouse in the calling workspace (or the merchant workspace named by X-Fulkruma-On-Behalf-Of for Pattern 2 partners). The first warehouse in a workspace is auto-flagged isDefault: true regardless of the request body; subsequent warehouses default to isDefault: false unless you opt in.
An Idempotency-Key header is required — see the API overview.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name |
string (1–120) | yes | Human-readable label. Shown on the dashboard and in shipping origin display. |
address |
string | no | Street address. Free-form. Required at rate-quote time; safe to skip on create and patch in later. |
city |
string | no | City name. Used for province-level rate matching. |
postal |
string | no | Postal code. |
lat |
number | no | Latitude (decimal degrees). Required if you intend to enable instant couriers (gosend, grab). |
lng |
number | no | Longitude (decimal degrees). |
phone |
string | no | Contact phone for the courier driver. |
isDefault |
boolean | no | Promote this warehouse to default. If you pass true, no other warehouse is demoted — you currently have to PATCH the prior default to isDefault: false yourself. The first warehouse always lands as default regardless. |
Response — 201 Created
{
"data": {
"warehouse": {
"id": "wh_01HXAB7K3M9N2P5QRS8TVWXY3Z",
"accountId": "acc_01HXxxxxxxxxxxxxxxxxxxxxxx",
"name": "Main warehouse",
"city": "Jakarta",
"isDefault": true,
"archived": false,
"createdAt": "2026-05-12T10:42:00.123Z",
"updatedAt": "2026-05-12T10:42:00.123Z"
}
},
"error": null,
"meta": { "requestId": "req_01HX...", "timestamp": "2026-05-12T10:42:00.124Z" }
}
Errors specific to this endpoint
| Status | error.code |
When |
|---|---|---|
400 |
VALIDATION |
name missing or longer than 120 chars; numeric fields not numeric. |
403 |
NO_ACCOUNT |
Token authenticated but has no accountId claim. |
Other 4xx/5xx errors follow the standard table in the API overview.
// Node
const { warehouse } = await fk.warehouses.create({
name: 'Main warehouse',
address: 'Jl. Sudirman 123',
city: 'Jakarta',
postal: '10220',
phone: '+628111111111',
});
# Python
warehouse = fk.warehouses.create(
name='Main warehouse',
address='Jl. Sudirman 123',
city='Jakarta',
postal='10220',
phone='+628111111111',
)['warehouse']
# curl
fulkruma_curl POST '/api/v1/warehouses' \
'{"name":"Main warehouse","address":"Jl. Sudirman 123","city":"Jakarta","postal":"10220"}'
Update a warehouse
PATCH /api/v1/warehouses/:id
Partial update — send only the fields you want to change. Omitted fields are left untouched. The accepted body is identical in shape to create, with every field optional.
Path parameters
| Param | Type | Description |
|---|---|---|
id |
string (wh_…) |
The warehouse to update. |
Errors
| Status | error.code |
When |
|---|---|---|
400 |
VALIDATION |
Field shape wrong. |
404 |
NOT_FOUND |
Warehouse doesn't exist or is in another workspace. |
Patch the prior default to
falsefirst. SettingisDefault: trueon a new warehouse does not demote the previous default; you'll have two defaults until you clear the old one. The portal does this in one transaction; the API requires two calls.
// Node
await fk.warehouses.update('wh_01HXAB7K3M9N2P5QRS8TVWXY3Z', {
lat: -6.2088,
lng: 106.8456,
});
# curl
fulkruma_curl PATCH '/api/v1/warehouses/wh_01HXAB7K3M9N2P5QRS8TVWXY3Z' \
'{"lat":-6.2088,"lng":106.8456}'
Archive a warehouse
DELETE /api/v1/warehouses/:id
Soft-archives the warehouse — sets archived: true. The row is not deleted: stock movement history, reservations, and shipments stay queryable and continue to reference it. Archived warehouses are excluded from the list endpoint and from the rate-quote source pool.
There is no hard delete. Archived warehouses can be unarchived by PATCHing archived: false if you ever need to. Stock currently sitting in the warehouse becomes inaccessible to new shipments until you reactivate it — transfer stock out first if you intend to retire the location.
Response — 200 OK
{ "data": { "archived": true }, "error": null, "meta": { ... } }
Errors
| Status | error.code |
When |
|---|---|---|
404 |
NOT_FOUND |
Warehouse doesn't exist or is in another workspace. |
The warehouse object
| Field | Type | Nullable | Description |
|---|---|---|---|
id |
string | no | Fulkruma ID. Always wh_ + 26-char ULID. Stable forever. |
accountId |
string | no | The workspace this warehouse belongs to. |
name |
string | no | Human-readable label. |
address |
string | yes | Street address. |
city |
string | yes | City name. |
postal |
string | yes | Postal code. |
lat |
number | yes | Latitude (decimal degrees). |
lng |
number | yes | Longitude (decimal degrees). |
phone |
string | yes | Driver-facing contact. |
isDefault |
boolean | no | Whether this warehouse is the implicit source for movements and shipments. |
archived |
boolean | no | Whether the warehouse is soft-archived. Archived warehouses don't appear in the list endpoint. |
createdAt |
string (ISO 8601 UTC) | no | Creation timestamp. |
updatedAt |
string (ISO 8601 UTC) | no | Last mutation timestamp. |
Events
| Event type | Fires on |
|---|---|
fulkruma.warehouse.created.v1 |
POST /api/v1/warehouses creates a warehouse. The payload is the new warehouse. |
Changing or archiving a warehouse emits no event: to mirror those into another system, poll GET /api/v1/warehouses and reconcile by updatedAt.
See the Webhooks resource for the event envelope, retry policy, and signature recipe.
Next
- Stock — per-variant per-warehouse quantity and the movement audit trail.
- Shipping — configure the shipping origin (separate from warehouse address) and pull rate quotes.
- Portal → Warehouses — the dashboard walkthrough.
- Authentication — the HMAC signing recipe.