verification
use it
# add to stunt.yaml
services:
anaplan:
adapter: embedded:anaplan-style
# then
$ stunt upThe embedded: source extracts this adapter from the binary — no git clone, fully offline.
how to mock the Anaplan API locally
Install stunt, paste the service block above into stunt.yaml, run stunt up — then point your client at localhost instead of Anaplan API. It works offline, keeps state across requests and restarts, and every response is synthetic: the route shapes, status codes, pagination, and webhook delivery follow the real Anaplan API 2.0 surface — the data is fake, the behavior is real.
backing stores
workspacestasks
api surface (18)
generated from the adapter manifest — exactly what boots, nothing more
18 routes
GET/2/0/workspaces
GET/2/0/workspaces/{workspaceId}/models
GET/2/0/workspaces/{workspaceId}/models/{modelId}/modules
GET/2/0/workspaces/{workspaceId}/models/{modelId}/files
GET/2/0/workspaces/{workspaceId}/models/{modelId}/files/{fileId}
POST/2/0/workspaces/{workspaceId}/models/{modelId}/files/{fileId}
PUT/2/0/workspaces/{workspaceId}/models/{modelId}/files/{fileId}
GET/2/0/workspaces/{workspaceId}/models/{modelId}/files/{fileId}/chunks
GET/2/0/workspaces/{workspaceId}/models/{modelId}/imports
GET/2/0/workspaces/{workspaceId}/models/{modelId}/exports
GET/2/0/workspaces/{workspaceId}/models/{modelId}/actions
GET/2/0/workspaces/{workspaceId}/models/{modelId}/processes
POST/2/0/workspaces/{workspaceId}/models/{modelId}/imports/{importId}/tasks
POST/2/0/workspaces/{workspaceId}/models/{modelId}/imports/{importId}/jobs
POST/2/0/workspaces/{workspaceId}/models/{modelId}/exports/{exportId}/tasks
POST/2/0/workspaces/{workspaceId}/models/{modelId}/exports/{exportId}/jobs
GET/2/0/workspaces/{workspaceId}/models/{modelId}/tasks/{taskId}
GET/2/0/workspaces/{workspaceId}/models/{modelId}
VM-verified behaviors (15)
- ✓missing or unrecognized credentials draw the 401 failure envelope
- ✓the workspace list is seeded with Anaplan paging metadata
- ✓paging walks the opaque offset cursor and rejects a bad token
- ✓models are workspace-scoped and a single model round-trips or 404s
- ✓catalog lists serve the seeded per-model action catalog
- ✓a full-body upload replaces file content byte-exact on POST and PUT
- ✓chunked uploads append in order and reject gaps and malformed ranges
- ✓invalid identifiers and unknown files get 400/404 envelopes
- ✓an import task walks CREATED → NOT_STARTED → IN_PROGRESS → COMPLETE
- ✓completion applies the import once and the export renders the model data
- ✓simulate_fail completes with every row failed
- ✓an import over an empty upload reports no contents
- ✓unknown import, export, and task ids get 404 failure envelopes
- ✓catalog ids resolve only within their model
- ✓task status is scoped to its workspace and model
Not implemented (4)
- No line-item, list, view, or module-data endpoints — data moves via CSV only
- No file DELETE; no workspace or model CRUD (catalogs are read-only)
- No ALM surface — revisions, comparisons, synthetic models
- No Anaplan token service (/token/authenticate) — Basic/Bearer only
Differs from the real API (5)
- Task state derives from the clock — IN_PROGRESS at +1s, COMPLETE at +3s
- simulate_fail in the task body is a simulator-only trigger (real Anaplan has none)
- PUT file upload is the same surface as POST; /jobs aliases /tasks
- links[0].href pinned to api.anaplan.com regardless of request host
- Unknown workspace/model scope returns 200 + empty items rather than 404
want more of the Anaplan API surface? adapters are YAML + Starlark — the authoring guide covers adding routes, fixtures, and state machines. Open an issue for anything big first, or just file a PR — merged routes ship in the next release.