Which API calls the SDK makes
The SDK makes exactly three kinds of request, all on the frames service. It does not call/v1/frames/admin, /v1/states, /v1/lgas, /v1/wards
or /v1/frames/insight, and it never looks frames up by box.
Get your key
The SDK needs one credential, an API key. Create it in your LOCI dashboard under Developers → New key: pick a scope and an expiry, and copy the secret, which is shown once. See Authentication for the full story, and Scopes for what each preset reaches.A key is read-only, acts for one organisation, and expires. A key narrowed
to named datasets only ever preloads those datasets. Every device that
uses the same key shares one rate-limit budget — see
cost.
Initialise the SDK
CallMilsatMaps.initialize once, for example in main, with the key you
created. After that, MilsatMaps.frames is the object every example here
uses. Call MilsatMaps.dispose when your app is done with it.
initialise the SDK
Preload your frames
You hand the SDK a list of frame ids. It fetches each frame’s outline and the data recorded on it, groups the data by layer, and gives back ready-made work areas. Call these methods in a prepare step before the map appears — when the user opens a project, say — not from a tap or a camera callback.load, then show
MapWorkArea with the frame id as its id; the dataset rows
sit under properties[MilsatFramePack.propertyKey], grouped by layer id.
Pass the list to controller.setWorkAreas, or to the prebuilt widget as
workAreas:. Frames arrive switched off, like any work area with
initiallyVisible false; the user turns them on, or you call
controller.showWorkArea(id). A frame is a work area, so every work-area
rule, including geofencing, applies.
What you get back
read a result
Finding ids to start from
A frame id is a string of digits. You can hold ids from your dashboard or your own records, or resolve them.- You have ids
- You have a point
- You have a polygon
- You have a box
Ids go straight to
loadFrames. An id the service does not know comes
back in missingIds, not as an error.Offline packs
A pack is a saved set of frames and their data, kept on the device under an id you choose (1–64 of letters, digits,_ or -). Nothing is cached
unless you call these; nothing refreshes a pack for you.
save, load, refresh, list, delete
Expiry.
maxAge on savePack/refreshPack marks a pack expired (not
deleted) after that long; loadPack then throws. With no maxAge a pack
never expires. Hidden layers passed to any call are left out when data
is stored and again when it is returned, so a hidden layer is not on the
map, not in the result, and not in the pack file.
Source: cloud or pack
loadFrames takes one source, so the two stores look like a single
choice.
the three sources
Errors and events
Failures are typed and the same on Android and iOS. None carries the key. Branch on the code, never on the message.handle each family
Service errors — MilsatFramesException
These mirror the API’s own error codes. The SDK adds three
transport codes the service never sends: network, untrusted_connection
and unknown.
The three key codes are final: the SDK does not retry them and emits a
MilsatFramesTokenRejected event. On rate_limited the SDK waits the
Retry-After time and tries up to three more times before surfacing the
error; do not loop on it. See Limits.
Pack errors
AMilsatFramesPackStoreException reports missing, expired,
wrongOrganisation or storageFailed. A MilsatFramesPackException
reports a damaged or foreign pack file (authenticationFailed, truncated,
badMagic, unsupportedVersion, corruptPayload). Every pack failure
closes: you get an error and no data, and nothing is deleted — a failed
read never destroys a pack a fix could recover. Call deletePack to get rid
of a bad one.
Events
listen for events
charged on each result.
Rate limits and cost
The limits and caps are the API’s own — the full detail is in Limits. ReadretryAfterSeconds on a rate_limited error rather
than any number here, because the numbers can change.
- Shared budget. Every device using the same key shares one bucket. A
whole team loading frames at 9am will see the first few succeed and the
rest get
rate_limited. Stagger syncs, or give large teams more than one key. - Load once, then work from a pack. Save a pack when the user opens a
project and use
packFirstorpackOnlyafter that. Do not refresh on startup, on a timer, or in a retry loop — each refresh spends requests again. - The cost of a load. The SDK sends at most 100 ids per request, one
request at a time, and a load makes two kinds of call (outlines and data),
so
Nids cost about2 × ceil(N / 100)requests. Resolving a point or a work area is one request. - Watch
charged. Some datasets are licensed per query and billed per request they contribute to; each refresh bills them again. - Watch
truncatedLayerIds. A layer at 200 features per request may be incomplete, and nothing else says so.

