Skip to main content

OmniLCS REST API Reference

The OmniLCS REST API is served over HTTPS on port 8443. The base URL is https://<host>:8443/api.

API documentation (Swagger UI) is available at https://<host>:8443/api/docs. The OpenAPI schema is at https://<host>:8443/api/schema.

Authentication

The API does not currently enforce authentication. Access should be restricted at the network level.

Response Format

All responses use JSON. Successful responses include a "status": "ok" field. Error responses include "status": "error" and a "reason" field.


System Status

GET /api/status

Returns system health and operational status.

Response (200)

{
"status": "ok",
"version": "1.0.0",
"name": "OmniLCS",
"diameter_peers": [
{
"host": "dra01.epc.mnc380.mcc313.3gppnetwork.org",
"realm": "epc.mnc380.mcc313.3gppnetwork.org",
"state": "Connected",
"transport": "sctp"
}
],
"active_sessions": 2,
"completed_sessions": 47,
"cells_loaded": 128,
"cell_sync": {
"last_sync": "2025-01-15T10:30:00Z",
"last_result": "ok (128 cells)",
"sync_count": 42
},
"uptime_seconds": 86400
}
FieldTypeDescription
versionstringApplication version
namestringInstance name
diameter_peersarrayConnected Diameter peers with state
active_sessionsintegerNumber of in-progress location sessions
completed_sessionsintegerNumber of completed location sessions
cells_loadedintegerNumber of cells in the database
cell_syncobjectInfluxDB sync status
uptime_secondsintegerProcess uptime in seconds

Location Services

POST /api/location

A single, harmonised "get location" call. The caller supplies the IMSI (and optionally a desired method/accuracy); OmniLCS decides which 3GPP LCS role and interface to use to satisfy it, and reports which one answered in the source field.

Every option is available here

OmniLCS is co-located as a GMLC and an E-SMLC (the LTE LCS network functions of TS 23.271) and also speaks MAP/Lg for legacy 2G/3G — so every standard way to locate a subscriber is reachable through this one endpoint:

Option3GPP roleInterface(s)How it locatesBest for
A — query the network (4G)GMLCSLh (TS 29.173) + SLg (TS 29.172)No active positioning — the serving MME returns the UE's serving cell (ECGI) from its contextFast, always-available coarse location; idle UEs (last-known)
B — actively position (4G)E-SMLCSLs / LCS-AP (TS 29.171), tunnelling LPP (TS 36.355) to the UE and LPPa (TS 36.455) to the eNBOmniLCS runs E-CID / GNSS / OTDOA against the UE and radioPrecise fixes when the UE/radio support it
C — query the network (2G/3G)GMLCMAP / Lg over SS7 (TS 29.002): SRI-for-LCS to the HLR, then ProvideSubscriberLocation to the serving MSC/SGSNThe serving MSC/SGSN returns the serving cell (Cell-ID / TA class)Subscribers camped on GERAN/UTRAN

Selection: for 4G, the requested method/accuracy chooses A (cell/last-known) or B (ecid/gnss/otdoa/hybrid). Setting rat to 2g/3g chooses C regardless of method. In A/B the serving MME is always in the path (SLg responder or SLs relay); in C the serving MSC/SGSN is. See 2G/3G location over MAP/Lg.

See Positioning Methods for how each method (Cell ID, E-CID, OTDOA, A-GNSS, hybrid) is obtained, their accuracy, and the accuracy→method auto-selection.

Request Body

{
"imsi": "001010000000001",
"method": "cell",
"location_type": 1,
"timeout": 30000,
"mme_host": "mme01.epc.mnc380.mcc313.3gppnetwork.org"
}
ParameterTypeRequiredDefaultDescription
imsistringYes--IMSI of the UE to locate
methodstringNocellPositioning method: cell, ecid, gnss, otdoa, hybrid. Active methods (ecid/gnss/otdoa/hybrid) drive the E-SMLC over SLs; cell uses an SLg PLR.
accuracyintegerNo--Requested horizontal accuracy in metres. If set, auto-selects the method (tighter → GNSS/OTDOA/E-CID); for the cell/last-known path it is also carried to the MME as LCS-QoS.
location_typeintegerNo1SLg-Location-Type (cell/last-known path): 0 current, 1 current or last known, 2 initial. The default 1 returns the last-known serving cell for idle UEs rather than failing a current-location request.
mme_hoststringNo--Destination-Host (serving MME). If omitted, it is resolved via an SLh LCS-Routing-Info-Request to the HSS.
ratstringNo4gRadio access technology. 2g/3g route over MAP/Lg (Option C) to the serving MSC/SGSN; 4g uses SLg/SLs (Options A/B) as selected by method.
node_gtstringNo--2G/3G only: serving MSC/SGSN global title. If omitted, it is resolved via a MAP SendRoutingInfoForLCS to the HLR.
timeoutintegerNo30000Timeout in milliseconds

The requested method (or accuracy) selects how OmniLCS positions the UE: active methods run the OmniLCS E-SMLC (LPP/LPPa over SLs), while cell/last-known queries the serving MME over SLg. On the SLg path the MME ultimately decides what it can return (typically the serving cell ECGI).

Response (200)

{
"status": "ok",
"imsi": "001010000000001",
"method": "cell",
"source": "slg",
"latitude": 40.7128,
"longitude": -74.0060,
"altitude": null,
"uncertainty": 10.5,
"confidence": null,
"cell_id": 43559,
"plmn": {"mcc": "001", "mnc": "01"},
"ecgi": "00F1100000AA27",
"serving_node": {"name": "mme01...", "realm": "epc..."},
"duration_ms": 5230,
"timestamp": "2025-01-15T10:30:00Z"
}

The response merges every field the positioner returned with the request envelope, so the exact set varies by path. latitude/longitude are decoded from the GAD Location-Estimate; source is "slg" for results from the serving MME over SLg, or the positioning method (gnss, ecid, …) for active E-SMLC fixes. Cell/SLg fixes additionally include the decoded ECGI (cell_id + plmn) alongside the raw ecgi. Binary AVPs (raw ECGI, GAD estimate, Serving-Node) are hex-encoded.

FieldTypeDescription
imsistringUE identifier
methodstringMethod requested
sourcestringActual positioning source used (slg, gnss, ecid, …)
latitudefloat/nullLatitude in decimal degrees
longitudefloat/nullLongitude in decimal degrees
altitudefloat/nullAltitude in meters (if available)
uncertaintyfloat/nullHorizontal position uncertainty in meters
uncertainty_altitudefloat/nullVertical uncertainty in meters (when present)
confidenceinteger/nullConfidence percentage
shapestring/nullGAD shape of the estimate (e.g. ellipsoid_point_with_uncertainty_circle)
cell_idinteger/nullDecoded E-UTRAN cell-id (cell/SLg path)
plmnobject/nullDecoded serving PLMN {mcc, mnc} (cell/SLg path)
ecgistring/nullRaw 7-byte ECGI, hex (cell/SLg path)
serving_nodeobject/nullServing MME identity (Name/Realm)
age_of_location_estimateinteger/nullAge of the estimate in minutes (when present)
accuracy_fulfilmentstring/nullWhether the requested accuracy was met
ecid_measurementsobject/nullE-CID radio measurements (ecid method)
duration_msintegerTime taken in milliseconds
timestampstringISO 8601 timestamp

Error Responses

StatusReasonDescription
400"imsi is required"Missing IMSI parameter
404"User not found"IMSI unknown
404"User not connected"UE not attached to network
422"No MME host available for this subscriber"No MME to route the request
504"Positioning timed out"Positioning method did not complete in time
500(varies)Internal error

Examples

Option A — coarse location via the GMLC role (SLh + SLg). Asking for cell (or any last-known request) resolves the serving MME and returns its serving cell:

curl -sk -X POST https://localhost:8443/api/location \
-H "Content-Type: application/json" \
-d '{"imsi": "001010000000001", "method": "cell"}'
{
"status": "ok",
"imsi": "001010000000001",
"method": "cell",
"source": "slg",
"latitude": -37.8183,
"longitude": 144.9671,
"altitude": null,
"uncertainty": 1273.5,
"confidence": null,
"cell_id": 43559,
"plmn": {"mcc": "001", "mnc": "01"},
"ecgi": "00F1100000AA27",
"serving_node": {"name": "mme01.epc.mnc001.mcc001.3gppnetwork.org", "realm": "epc.mnc001.mcc001.3gppnetwork.org"},
"duration_ms": 412,
"timestamp": "2026-06-22T01:14:55.218000Z"
}

Option B — precise location via the E-SMLC role (SLs / LPP). Asking for gnss (or supplying a tight accuracy) drives an active fix; source reflects the method that answered:

curl -sk -X POST https://localhost:8443/api/location \
-H "Content-Type: application/json" \
-d '{"imsi": "001010000000001", "method": "gnss", "timeout": 30000}'
{
"status": "ok",
"imsi": "001010000000001",
"method": "gnss",
"source": "gnss",
"latitude": -37.8200,
"longitude": 144.9834,
"altitude": 558,
"uncertainty": 9.5,
"uncertainty_altitude": 1.1,
"confidence": 90,
"shape": "ellipsoid_point_with_altitude_and_uncertainty_ellipsoid",
"duration_ms": 10077,
"timestamp": "2026-06-22T01:18:02.640000Z"
}

Equivalently, -d '{"imsi": "001010000000001", "accuracy": 20}' auto-selects A-GNSS (≤ 50 m → A-GNSS) and returns the same shape of response.


GET /api/location

List recent completed location fixes.

Query Parameters

ParameterTypeDefaultDescription
limitinteger50Maximum number of results

Response (200)

{
"status": "ok",
"data": [
{
"imsi": "001010000000001",
"method": "gnss",
"state": "completed",
"latitude": 40.7128,
"longitude": -74.0060,
"uncertainty": 10.5,
"source": "gnss",
"created_at": "2025-01-15T10:29:55Z",
"completed_at": "2025-01-15T10:30:00Z"
}
],
"count": 1
}

GET /api/location/:imsi

Get the last known location for a UE by IMSI.

Path Parameters

ParameterTypeDescription
imsistringIMSI of the UE

Response (200)

{
"status": "ok",
"imsi": "001010000000001",
"latitude": 40.7128,
"longitude": -74.0060,
"altitude": null,
"uncertainty": 10.5,
"confidence": null,
"source": "gnss",
"timestamp": "2025-01-15T10:30:00Z"
}

Error Responses

StatusReason
404"No location found for IMSI"
404"No completed location for IMSI"

GET /api/location/:imsi/history

Get location fix history for an IMSI.

Path Parameters

ParameterTypeDescription
imsistringIMSI of the UE

Query Parameters

ParameterTypeDefaultDescription
fromstring--Start of time range (ISO 8601 or date)
tostring--End of time range (ISO 8601 or date)
limitinteger100Maximum number of results

Response (200)

{
"status": "ok",
"data": [
{
"timestamp": "2025-01-15T10:30:00Z",
"imsi": "001010000000001",
"method": "gnss",
"latitude": 40.7128,
"longitude": -74.0060,
"altitude": null,
"uncertainty": 10.5,
"confidence": null,
"source": "gnss",
"duration_ms": 5230
}
],
"count": 1
}

GET /api/location/:imsi/history/csv

Export location history for an IMSI as a CSV file.

Path Parameters

ParameterTypeDescription
imsistringIMSI of the UE

Query Parameters

Same as /api/location/:imsi/history.

Response (200)

Returns a CSV file download with headers:

timestamp,imsi,method,latitude,longitude,altitude,uncertainty,confidence,source,duration_ms

Content-Type: text/csv Content-Disposition: attachment; filename="location_history_<imsi>_<date>.csv"


Cell Database

GET /api/cells

List all cells in the database.

Response (200)

{
"status": "ok",
"data": [
{
"cell_id": "001-01-0001-01",
"latitude": 40.7128,
"longitude": -74.0060,
"pci": 100,
"earfcn": 1300,
"radius": 500,
"azimuth": null,
"height": null,
"prs_config": null,
"updated_at": "2025-01-15T10:00:00Z"
}
],
"count": 1
}

GET /api/cells/:id

Get a single cell by cell_id.

Path Parameters

ParameterTypeDescription
idstringCell identifier

Response (200)

{
"status": "ok",
"data": {
"cell_id": "001-01-0001-01",
"latitude": 40.7128,
"longitude": -74.0060,
"pci": 100,
"earfcn": 1300,
"radius": 500,
"azimuth": null,
"height": null,
"prs_config": {
"bandwidth": 50,
"config_index": 0,
"num_dl_frames": 1,
"cp_length": null,
"num_antenna_ports": null
},
"updated_at": "2025-01-15T10:00:00Z"
}
}

Error Response

StatusReason
404"Cell not found: <id>"

POST /api/cells

Create a new cell.

Request Body

{
"cell_id": "001-01-0001-01",
"latitude": 40.7128,
"longitude": -74.0060,
"pci": 100,
"earfcn": 1300,
"radius": 500,
"azimuth": 120.0,
"height": 30.0,
"prs_config": {
"bandwidth": 50,
"config_index": 0,
"num_dl_frames": 1,
"cp_length": "normal",
"num_antenna_ports": 2
}
}
ParameterTypeRequiredDefaultDescription
cell_idstringYes--Unique cell identifier
latitudefloatYes--Cell latitude (-90 to 90)
longitudefloatYes--Cell longitude (-180 to 180)
pciintegerNo--Physical Cell Identity (0-503)
earfcnintegerNo--E-UTRA Absolute Radio Frequency Channel Number
radiusintegerNo1000Coverage radius in meters
azimuthfloatNo--Antenna azimuth in degrees
heightfloatNo--Antenna height in meters
prs_configobjectNo--PRS configuration for OTDOA
tacintegerNo--Tracking Area Code (used for 4G CAP alert broadcast targeting)
lacintegerNo--Location Area Code (used for 2G and 3G CAP alert broadcast targeting)
ratstringNo--Radio Access Technology: "4g", "3g", or "2g"

Response (201)

Returns the created cell in the same format as GET /api/cells/:id.

Error Responses

StatusReason
400"cell_id is required"
400"latitude and longitude are required"

PUT /api/cells/:id

Update an existing cell. Only provided fields are updated.

Path Parameters

ParameterTypeDescription
idstringCell identifier

Request Body

Any cell fields to update (same as POST, but all fields are optional).

Response (200)

Returns the updated cell.

Error Response

StatusReason
404"Cell not found: <id>"

DELETE /api/cells/:id

Delete a cell from the database.

Path Parameters

ParameterTypeDescription
idstringCell identifier

Response (204)

Empty body on success.

Error Response

StatusReason
404"Cell not found: <id>"

GET /api/cells/nearby

Find cells near a geographic point.

Query Parameters

ParameterTypeRequiredDefaultDescription
latfloatYes--Latitude of search center
lonfloatYes--Longitude of search center
radiusfloatNo10Search radius in kilometers

Response (200)

{
"status": "ok",
"data": [
{
"cell_id": "001-01-0001-01",
"latitude": 40.7128,
"longitude": -74.0060,
"pci": 100,
"earfcn": 1300,
"distance_km": 0.523
}
],
"count": 1
}

Results are sorted by distance (nearest first). Each entry includes a distance_km field.

Error Response

StatusReason
400"lat and lon query parameters are required"

POST /api/cells/sync

Trigger an immediate InfluxDB cell sync.

Request Body

None required.

Response (200)

{
"status": "ok",
"cells_synced": 128
}

Error Responses

StatusReason
500"Sync failed: <reason>"
503"Cell sync service unavailable"

Deferred Location (GMLC)

Manage periodic and geo-fence triggered location sessions. See the GMLC & Le Interface guide for full details on session types and Diameter integration.

GET /api/deferred_location

List all active deferred location sessions.

Response (200):

{
"status": "ok",
"count": 1,
"data": [
{
"session_id": "a1b2c3d4-e5f6-...",
"type": "periodic",
"imsi": "001010000000001",
"method": "cell",
"client_name": "rest-api",
"status": "active",
"interval_ms": 60000,
"remaining_reports": 7,
"total_reports": 10,
"started_at": "2026-04-09T10:00:00Z",
"last_fix_at": "2026-04-09T10:03:00Z"
}
]
}

POST /api/deferred_location

Create a new deferred location session.

Periodic session request body:

{
"type": "periodic",
"imsi": "001010000000001",
"method": "cell",
"interval_seconds": 60,
"count": 10
}
FieldTypeRequiredDescription
typestringYes"periodic"
imsistringYesSubscriber IMSI
methodstringNoPositioning method: cell, ecid, gnss, otdoa. Default: cell
interval_secondsintegerYesSeconds between fixes
countintegerYesTotal number of fixes to perform

Triggered session request body:

{
"type": "triggered",
"imsi": "001010000000001",
"method": "cell",
"event_type": "entering",
"poll_interval_seconds": 30,
"max_reports": 0,
"areas": [
{
"type": "circle",
"center": {"lat": -33.8688, "lon": 151.2093},
"radius_meters": 500
}
]
}
FieldTypeRequiredDescription
typestringYes"triggered"
imsistringYesSubscriber IMSI
methodstringNoPositioning method. Default: cell
event_typestringYes"entering", "leaving", or "being_inside"
poll_interval_secondsintegerNoSeconds between position polls. Default: 30
max_reportsintegerNoMax trigger reports. 0 = unlimited
areasarrayYesList of area definitions (circle or polygon)

Response (201):

{"status": "ok", "message": "Periodic session created"}

GET /api/deferred_location/:session_id

Get the status of a deferred session.

Response (200):

{
"status": "ok",
"data": {
"session_id": "a1b2c3d4-...",
"type": "periodic",
"imsi": "001010000000001",
"status": "active",
"remaining_reports": 7,
"total_reports": 10
}
}

DELETE /api/deferred_location/:session_id

Cancel an active deferred session.

Response (200):

{"status": "ok", "message": "Session cancelled"}
StatusError
400Missing or invalid parameters
404Session not found

CAP Alerts

POST /api/cap

Submit a CAP XML alert for processing. The alert is parsed, polygon warning areas are resolved to TACs/LACs via the cell database, and the alert is either queued for approval or auto-broadcast depending on configuration.

Request Body

{
"xml": "<alert xmlns=\"urn:oasis:names:tc:emergency:cap:1.2\">...</alert>"
}
ParameterTypeRequiredDescription
xmlstringYesComplete CAP v1.2 XML alert document

Response (201)

{
"status": "ok",
"data": {
"id": "a1b2c3d4-e5f6-...",
"status": "pending",
"source": "http_post",
"received_at": "2025-01-15T10:30:00Z",
"matched_cells": 42,
"tacs": [100, 101],
"lacs": [5001],
"mcc": "001",
"mnc": "01",
"broadcast_params": {
"message_id": 4370,
"repetition_period": 30,
"num_broadcasts": 10,
"message_text": "Tornado Warning...",
"event": "Tornado Warning",
"severity": "Extreme",
"urgency": "Immediate"
}
}
}

The status field is "pending" when require_approval is true, or "sent" when auto-approved.

Error Responses

StatusReason
400"xml field is required"
422Parse error details

GET /api/cap

List all alerts across all states (pending, active, history).

Response (200)

{
"status": "ok",
"data": {
"pending": [...],
"active": [...],
"history": [...]
}
}

GET /api/cap/:id

Get a single alert by ID.

Path Parameters

ParameterTypeDescription
idstringAlert UUID

Response (200)

Returns the alert object.

Error Response

StatusReason
404"Alert not found: <id>"

PUT /api/cap/:id

Approve or reject a pending alert.

Request Body

{
"action": "approve",
"operator": "operator1"
}
ParameterTypeRequiredDescription
actionstringYes"approve" or "reject"
operatorstringNoOperator name for audit trail (defaults to "unknown")

Response (200)

Returns the updated alert object.

Error Responses

StatusReason
400"action must be 'approve' or 'reject'"
404"Alert not found: <id>"

Error Response Format

All error responses follow this structure:

{
"status": "error",
"reason": "Human-readable error description"
}

Common HTTP status codes:

CodeMeaning
200Success
201Created (cell creation)
204No Content (cell deletion)
400Bad Request (missing or invalid parameters)
404Not Found (unknown resource)
422Unprocessable Entity (valid request but cannot be fulfilled)
500Internal Server Error
503Service Unavailable
504Gateway Timeout (positioning timeout)