PyHSS ships with a Flask-RESTX based HTTP API that exposes CRUD operations on every object in the subscriber database, plus a range of OAM (Operations, Administration & Maintenance) and dynamic PCRF functions.
It is the recommended way to provision and operate PyHSS. If you would rather work
directly in Python, lib/database.py exposes the same hooks the API calls
internally.
- Quick reference
- Running the API service
- Interactive documentation (Swagger)
- Request basics
- Authentication
- Conventions
- Error handling
- End-to-end provisioning walkthrough
- Endpoint reference
- Integrating from Python
| Namespace | Base path | Purpose |
|---|---|---|
| APN | /apn |
Access Point Name profiles |
| AUC | /auc |
SIM / authentication data (Ki, OPc, AMF, SQN) and vector generation |
| Subscriber | /subscriber |
EPC subscriber profiles & APN routing |
| IMS Subscriber | /ims_subscriber |
IMS / VoLTE subscriber profiles |
| TFT | /tft |
Traffic Flow Templates |
| Charging Rule | /charging_rule |
Predefined PCC / charging rules |
| EIR | /eir |
Equipment Identity Register rules & history |
| Subscriber Attributes | /subscriber_attributes |
Arbitrary key/value metadata per subscriber |
| Roaming | /roaming |
Roaming networks & rules |
| IFC Template | /ifc_template |
Initial Filter Criteria (iFC) templates |
| Operation Logs | /operation_logs |
Audit trail of write operations |
| OAM | /oam |
Health, peers, de-registration, reconciliation, rollback |
| PCRF | /pcrf |
Dynamic Gx actions (rule push, CLR, PCSCF restoration, emergency subs) |
| GeoRed | /geored |
Geographic redundancy state push & peer management |
| Push | /push |
Asynchronous Diameter commands (e.g. CLR) |
The base path of every endpoint is the namespace itself (for example
http://hssip:8080/subscriber/). There is no/api/v1prefix.
The API service listens on TCP port 8080 and binds to 0.0.0.0.
Run it directly:
python3 services/apiService.pyRun it as a container by setting CONTAINER_ROLE=api (see docker/docker-compose.yaml):
cd docker && docker compose up --build -dRun it as a service with the bundled unit file systemd/pyhss_api.service.
For production deployments, PyHSS API uses Flask and can be served behind your preferred WSGI server.
Once the service is running, browse to:
http://hssip:8080/docs/
This is the Swagger UI, generated from the live models. It documents every field of every object, and includes a "Try it out" feature so you can issue requests directly from the browser.
The raw OpenAPI definition is available at:
http://hssip:8080/swagger.json
This can be fed into client generators (openapi-generator, swagger-codegen, …)
to produce typed SDKs in your language of choice.
- All request and response bodies are JSON.
- Send
Content-Type: application/jsonon every request that carries a body (PUT/PATCH). - The HTTP verbs follow REST conventions:
| Verb | Meaning |
|---|---|
GET |
Read a single object or a list |
PUT |
Create a new object |
PATCH |
Update an existing object |
DELETE |
Delete an object |
Note that creation uses
PUT, notPOST.
CORS is enabled for all origins, and the service echoes the configured
OriginHost back in an HSS response header.
Authentication is controlled by two hss configuration keys:
hss:
lock_provisioning: False # default
provisioning_key: "changeThisKeyInProduction"(or the equivalent environment variables HSS_LOCK_PROVISIONING and
HSS_PROVISIONING_KEY when running in Docker.)
- When
lock_provisioningisFalse(the default), the API is open and no credentials are required. - When
lock_provisioningisTrue, every write request (PUT/PATCH/DELETE) must include the provisioning key in aProvisioning-Keyheader. Read-onlyGETrequests remain open, except for a small number of state-changing OAMGETendpoints (such as the rollback endpoints) that are also protected.
curl -X PUT 'http://hssip:8080/apn/' \
-H 'Content-Type: application/json' \
-H 'Provisioning-Key: changeThisKeyInProduction' \
-d '{ "apn": "internet", ... }'If the key is missing or wrong, the API responds with 401 and:
{ "Result": "Unauthorized - Provisioning-Key Invalid" }The Swagger UI (
/docs),/swagger.jsonand/metricsare always reachable without a key.
By default the AuC GET endpoints redact the secret key material (ki, opc).
To allow the API to return these values, set api.enable_insecure_auc: True.
Leave this disabled in production.
Auto-generated IDs. When creating an object you do not supply its primary
key (apn_id, auc_id, subscriber_id, …). PyHSS assigns it and returns the full
object, including the new ID, in the create response.
last_modified. Every object carries a last_modified timestamp that PyHSS
maintains automatically. It is returned on reads but you never need to set it.
Pagination. All …/list endpoints accept two optional query parameters:
| Parameter | Default | Meaning |
|---|---|---|
page |
0 |
Zero-based page index |
page_size |
api.page_size config value (100) |
Items per page |
curl 'http://hssip:8080/subscriber/list?page=0&page_size=50'Operation IDs & rollback. Write endpoints accept an optional operation_id
query parameter. Operations sharing the same operation_id are grouped together in
the audit log, so they can be rolled back as a unit via the
/oam/rollback_operation/... endpoints.
curl -X PUT 'http://hssip:8080/apn/?operation_id=batch-2024-06-01' \
-H 'Content-Type: application/json' -d '{ ... }'Responses use standard HTTP status codes:
| Status | Meaning |
|---|---|
200 |
Success |
400 |
Bad request / database integrity or operational error |
401 |
Missing or invalid Provisioning-Key |
404 |
Object or route not found |
410 |
Required external resource missing (e.g. EIR CSV file not defined) |
500 |
Unhandled internal error |
Error bodies follow this shape:
{
"result": "Failed",
"reason": "A database integrity error occurred: ..."
}A minimal flow to bring a subscriber onto data and voice services. Each step builds
on the IDs returned by the previous step. (Add -H 'Provisioning-Key: ...' to the
write requests if lock_provisioning is enabled.)
At a minimum, supply the Ki, OPc and AMF. (If you only have the OP, convert it to
OPc with lib/CryptoTool.py.)
curl -X PUT 'http://hssip:8080/auc/' \
-H 'Content-Type: application/json' \
-d '{
"ki": "465B5CE8B199B49FAA5F0A2EE238A6BC",
"opc": "E8ED289DEBA952E4283B54E88E6183CA",
"amf": "8000",
"sqn": 0
}'Response (truncated) — note the assigned auc_id:
{ "auc_id": 1, "amf": "8000", "sqn": 0, ... }curl -X PUT 'http://hssip:8080/apn/' \
-H 'Content-Type: application/json' \
-d '{
"apn": "internet",
"apn_ambr_dl": 9999999,
"apn_ambr_ul": 9999999,
"qci": 9,
"arp_priority": 1,
"arp_preemption_capability": true,
"arp_preemption_vulnerability": false
}'Response: { "apn_id": 1, ... }.
Reference the auc_id from step 1 and the apn_id(s) from step 2.
The allowed APNs are tracked per Diameter interface:
apn_list— comma-separated APN IDs returned in the S6a Update-Location-Answer (mobile / 3GPP access via the MME). Required.apn_list_swx— comma-separated APN IDs returned in the SWx Server-Assignment-Answer (untrusted non-3GPP access via the ePDG). Optional. When NULL or empty the SWx SAA is rejected withDIAMETER_ERROR_USER_NO_NON_3GPP_SUBSCRIPTION (5450)per 3GPP TS 29.273 §5.2.2.4, so VoWiFi attach is denied. Operators that want VoWiFi must list at least the IMS APN here.
curl -X PUT 'http://hssip:8080/subscriber/' \
-H 'Content-Type: application/json' \
-d '{
"imsi": "001010000000001",
"enabled": true,
"auc_id": 1,
"default_apn": 1,
"apn_list": "1",
"apn_list_swx": "1",
"msisdn": "491792021244",
"ue_ambr_dl": 9999999,
"ue_ambr_ul": 9999999,
"nam": 0,
"subscribed_rau_tau_timer": 600
}'The Initial Filter Criteria (iFC) returned to the S-CSCF are sourced from a
database-stored template, referenced by IMS subscribers via ifc_template_id.
Create the template first — template_content is a Jinja2 XML document (the
iFC_vars placeholders are filled in per-subscriber at registration time):
curl -X PUT 'http://hssip:8080/ifc_template/' \
-H 'Content-Type: application/json' \
-d '{
"name": "default_ifc",
"description": "Default VoLTE iFC",
"template_content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><IMSSubscription>...</IMSSubscription>"
}'Response: { "ifc_template_id": 1, ... }. You can fetch a template by name with
GET /ifc_template/name/default_ifc.
Reference the ifc_template_id from step 4. Multiple MSISDNs can be supplied as
comma-separated values in msisdn_list.
curl -X PUT 'http://hssip:8080/ims_subscriber/' \
-H 'Content-Type: application/json' \
-d '{
"imsi": "001010000000001",
"msisdn": "491792021244",
"msisdn_list": "491792021244",
"ifc_template_id": 1,
"xcap_profile": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><simservs>...</simservs>"
}'The subscriber is now able to attach for data and register to the IMS.
The older
ifc_pathfield (a path to an iFC template file on disk) is deprecated — useifc_template_idto reference a database-stored iFC template instead.
Below is a per-namespace reference. The exact set of fields for each object is generated live from the database schema, so always consult the Swagger UI for the authoritative, version-specific field list. The examples here use representative fields.
| Method & path | Description |
|---|---|
PUT /apn/ |
Create an APN |
GET /apn/<apn_id> |
Get an APN |
PATCH /apn/<apn_id> |
Update an APN |
DELETE /apn/<apn_id> |
Delete an APN |
GET /apn/list |
List APNs (paginated) |
# Create
curl -X PUT 'http://hssip:8080/apn/' -H 'Content-Type: application/json' \
-d '{"apn":"ims","apn_ambr_dl":256000,"apn_ambr_ul":256000,"qci":5,
"arp_priority":1,"arp_preemption_capability":true,"arp_preemption_vulnerability":false}'
# Read
curl 'http://hssip:8080/apn/1'| Method & path | Description |
|---|---|
PUT /auc/ |
Create AuC (SIM) data |
GET /auc/<auc_id> |
Get AuC entry by ID |
PATCH /auc/<auc_id> |
Update AuC entry |
DELETE /auc/<auc_id> |
Delete AuC entry |
GET /auc/list |
List AuC entries (paginated) |
GET /auc/iccid/<iccid> |
Find AuC entry by ICCID |
GET /auc/imsi/<imsi> |
Find AuC entry by IMSI |
GET /auc/eap_aka/plmn/<plmn>/imsi/<imsi> |
Generate EAP-AKA vectors (VoWiFi) |
GET /auc/aka/vector_count/<count>/imsi/<imsi> |
Generate <count> EPS-AKA vectors |
GET /auc/aka/resync/imsi/<imsi>/auts/<auts>/rand/<rand> |
Re-synchronise SQN using AUTS |
# Generate 3 EPS-AKA authentication vectors for an IMSI
curl 'http://hssip:8080/auc/aka/vector_count/3/imsi/001010000000001'By default
ki/opcare redacted from AuC reads. Enableapi.enable_insecure_auconly if you must retrieve them via the API.
| Method & path | Description |
|---|---|
PUT /subscriber/ |
Create a subscriber |
GET /subscriber/<subscriber_id> |
Get subscriber by ID |
PATCH /subscriber/<subscriber_id> |
Update subscriber |
DELETE /subscriber/<subscriber_id> |
Delete subscriber |
GET /subscriber/list |
List subscribers (paginated) |
GET /subscriber/imsi/<imsi> |
Get subscriber by IMSI |
GET /subscriber/msisdn/<msisdn> |
Get subscriber by MSISDN |
PUT /subscriber/routing/ |
Create a subscriber→APN routing entry |
GET /subscriber/routing/<subscriber_id>/<apn_id> |
Get a routing entry |
DELETE /subscriber/routing/<subscriber_id>/<apn_id> |
Delete a routing entry |
PATCH /subscriber/routing/<subscriber_routing_id> |
Update a routing entry |
curl 'http://hssip:8080/subscriber/imsi/001010000000001'Reads by IMSI/MSISDN also include the subscriber's attributes (see
Subscriber Attributes).
| Method & path | Description |
|---|---|
PUT /ims_subscriber/ |
Create an IMS subscriber |
GET /ims_subscriber/<ims_subscriber_id> |
Get by ID |
PATCH /ims_subscriber/<ims_subscriber_id> |
Update |
DELETE /ims_subscriber/<ims_subscriber_id> |
Delete |
GET /ims_subscriber/list |
List (paginated) |
GET /ims_subscriber/ims_subscriber_msisdn/<msisdn> |
Get by MSISDN |
GET /ims_subscriber/ims_subscriber_imsi/<imsi> |
Get by IMSI |
Traffic Flow Templates referenced by charging rules via tft_group_id.
| Method & path | Description |
|---|---|
PUT /tft/ |
Create a TFT |
GET /tft/<tft_id> |
Get a TFT |
PATCH /tft/<tft_id> |
Update a TFT |
DELETE /tft/<tft_id> |
Delete a TFT |
GET /tft/list |
List TFTs (paginated) |
curl -X PUT 'http://hssip:8080/tft/' -H 'Content-Type: application/json' \
-d '{"tft_group_id":1,"tft_string":"permit out ip from any to any","direction":1}'direction: 0 unspecified, 1 downlink, 2 uplink, 3 bidirectional.
| Method & path | Description |
|---|---|
PUT /charging_rule/ |
Create a charging rule |
GET /charging_rule/<charging_rule_id> |
Get a charging rule |
PATCH /charging_rule/<charging_rule_id> |
Update a charging rule |
DELETE /charging_rule/<charging_rule_id> |
Delete a charging rule |
GET /charging_rule/list |
List charging rules (paginated) |
curl -X PUT 'http://hssip:8080/charging_rule/' -H 'Content-Type: application/json' \
-d '{"rule_name":"voice","qci":1,"arp_priority":5,
"arp_preemption_capability":true,"arp_preemption_vulnerability":false,
"mbr_dl":128000,"mbr_ul":128000,"gbr_dl":128000,"gbr_ul":128000,
"tft_group_id":1,"precedence":100,"rating_group":4000}'To retrieve a rule together with its resolved TFT list, use GET /pcrf/<charging_rule_id>.
Equipment Identity Register match rules and IMSI/IMEI sighting history.
| Method & path | Description |
|---|---|
PUT /eir/ |
Create an EIR rule |
GET /eir/<eir_id> |
Get an EIR rule |
PATCH /eir/<eir_id> |
Update an EIR rule |
DELETE /eir/<eir_id> |
Delete an EIR rule |
GET /eir/list |
List EIR rules (paginated) |
GET /eir/lookup_imei/<imei> |
Look up TAC/IMEI metadata |
GET /eir/eir_history/<attribute> |
Get IMSI/IMEI history for an attribute |
DELETE /eir/eir_history/<attribute> |
Delete history for an attribute |
GET /eir/eir_history/list |
List IMSI/IMEI history (paginated) |
# Blacklist any IMEI starting with 777 for a specific IMSI (regex mode)
curl -X PUT 'http://hssip:8080/eir/' -H 'Content-Type: application/json' \
-d '{"imei":"^777.*","imsi":"^001010000000001$","regex_mode":1,"match_response_code":1}'regex_mode: 0 exact match, 1 regex. match_response_code: 0 whitelist,
1 blacklist, 2 greylist.
A key/value store for attaching arbitrary metadata (external IDs, customer names, integration data) to a subscriber.
| Method & path | Description |
|---|---|
PUT /subscriber_attributes/ |
Create an attribute |
GET /subscriber_attributes/<subscriber_id> |
List attributes for a subscriber |
PATCH /subscriber_attributes/<subscriber_attributes_id> |
Update an attribute |
DELETE /subscriber_attributes/<subscriber_attributes_id> |
Delete an attribute |
GET /subscriber_attributes/list |
List all attributes (paginated) |
curl -X PUT 'http://hssip:8080/subscriber_attributes/' -H 'Content-Type: application/json' \
-d '{"subscriber_id":1,"key":"CustomerName","value":"Example Corp"}'| Method & path | Description |
|---|---|
PUT /roaming/network/ |
Create a roaming network (MCC/MNC) |
GET /roaming/network/<roaming_network_id> |
Get a roaming network |
PATCH /roaming/network/<roaming_network_id> |
Update a roaming network |
DELETE /roaming/network/<roaming_network_id> |
Delete a roaming network |
GET /roaming/network/list |
List roaming networks (paginated) |
PUT /roaming/rule/ |
Create a roaming rule (allow/deny per network) |
GET /roaming/rule/<roaming_rule_id> |
Get a roaming rule |
PATCH /roaming/rule/<roaming_rule_id> |
Update a roaming rule |
DELETE /roaming/rule/<roaming_rule_id> |
Delete a roaming rule |
GET /roaming/rule/list |
List roaming rules (paginated) |
curl -X PUT 'http://hssip:8080/roaming/network/' -H 'Content-Type: application/json' \
-d '{"name":"Partner DE","preference":1,"mcc":"262","mnc":"02"}'
curl -X PUT 'http://hssip:8080/roaming/rule/' -H 'Content-Type: application/json' \
-d '{"roaming_network_id":1,"allow":true,"enabled":true}'Reusable Jinja2 XML templates for Initial Filter Criteria.
| Method & path | Description |
|---|---|
PUT /ifc_template/ |
Create a template |
GET /ifc_template/<ifc_template_id> |
Get a template |
PATCH /ifc_template/<ifc_template_id> |
Update a template (invalidates cache) |
DELETE /ifc_template/<ifc_template_id> |
Delete a template (invalidates cache) |
GET /ifc_template/list |
List templates (paginated) |
GET /ifc_template/name/<template_name> |
Get a template by name |
POST /ifc_template/cache/invalidate |
Invalidate all cached templates |
POST /ifc_template/cache/invalidate/<ifc_template_id> |
Invalidate one cached template |
curl -X PUT 'http://hssip:8080/ifc_template/' -H 'Content-Type: application/json' \
-d '{"name":"default_ifc","description":"Default VoLTE iFC",
"template_content":"<?xml version=\"1.0\" encoding=\"UTF-8\"?><IMSSubscription>...</IMSSubscription>"}'IMS subscribers reference a template by its ifc_template_id. Editing or deleting
a template publishes a cache-invalidation message so the new content is picked up
without a restart.
Read-only audit trail of all write operations.
| Method & path | Description |
|---|---|
GET /operation_logs/list |
List operation logs (paginated) |
GET /operation_logs/last |
Get the most recent operation |
GET /operation_logs/list/table/<table_name> |
List operations for a table (paginated) |
Operations and maintenance functions.
| Method & path | Description |
|---|---|
GET /oam/ping |
Liveness check — returns {"result": "OK"} |
GET /oam/diameter_peers |
List currently connected Diameter peers |
GET /oam/serving_subs |
Subscribers currently served by the HSS |
GET /oam/serving_subs_pcrf |
Subscribers currently served by the PCRF |
GET /oam/serving_subs_ims |
Subscribers currently served by the IMS |
GET /oam/deregister/<imsi> |
De-register an IMSI from the whole network (CLR/RTR/CCR-T) |
GET /oam/reconcile/ims/<imsi> |
Compare IMS location across all GeoRed HSS nodes |
GET /oam/reconcile/enum |
Rebuild all ENUM/NAPTR records from the IMS database |
GET /oam/rollback_operation/last |
Roll back the last write operation |
GET /oam/rollback_operation/<operation_id> |
Roll back all writes for an operation_id |
# Health probe
curl 'http://hssip:8080/oam/ping'
# See which Diameter peers are connected
curl 'http://hssip:8080/oam/diameter_peers'Dynamic Gx / Rx actions against currently attached subscribers, plus emergency subscriber management.
| Method & path | Description |
|---|---|
PUT /pcrf/ |
Push a predefined charging rule to a subscriber (Gx RAR) |
GET /pcrf/<charging_rule_id> |
Get a charging rule with its resolved TFT list |
PUT /pcrf/clr_subscriber |
Trigger a Cancel Location Request for a subscriber |
PUT /pcrf/pcscf_restoration_subscriber |
Trigger P-CSCF restoration for one IMS subscriber |
PUT /pcrf/pcscf_restoration |
Trigger P-CSCF restoration for all subscribers on a P-CSCF |
GET /pcrf/pcrf_subscriber/list |
List all PCRF-served subscribers |
GET /pcrf/pcrf_subscriber_imsi/<imsi> |
PCRF session info for an IMSI (all APNs) |
GET /pcrf/pcrf_subscriber_imsi/<imsi>/<apn_id> |
PCRF session info for an IMSI on one APN |
GET /pcrf/pcrf_serving_apn_ip/<ip_address> |
Find the serving APN by UE IP |
GET /pcrf/subscriber_routing/<subscriber_routing> |
Look up a subscriber routing entry |
PUT /pcrf/emergency_subscriber/ |
Create an emergency subscriber |
GET /pcrf/emergency_subscriber/<emergency_subscriber_id> |
Get an emergency subscriber |
PATCH /pcrf/emergency_subscriber/<emergency_subscriber_id> |
Update an emergency subscriber |
DELETE /pcrf/emergency_subscriber/<emergency_subscriber_id> |
Delete an emergency subscriber |
GET /pcrf/emergency_subscriber/list |
List emergency subscribers (paginated) |
# Install charging rule 1 on APN 1 for an attached subscriber
curl -X PUT 'http://hssip:8080/pcrf/' -H 'Content-Type: application/json' \
-d '{"imsi":"001010000000001","apn_id":1,"charging_rule_id":1}'Geographic redundancy state replication. The PATCH /geored/ endpoint is normally
called by peer HSS nodes, not by integrators.
| Method & path | Description |
|---|---|
PATCH /geored/ |
Apply pushed GeoRed state (MME/CSCF/APN/EIR/SQN/emergency, …) |
GET /geored/ |
Return the active GeoRed schema |
GET /geored/peers |
List configured GeoRed peers |
PATCH /geored/peers |
Replace the list of GeoRed peer endpoints |
GET /geored/webhooks |
List configured webhook endpoints |
| Method & path | Description |
|---|---|
PUT /push/clr/<imsi> |
Push a Cancel Location Request to a specific MME |
curl -X PUT 'http://hssip:8080/push/clr/001010000000001' \
-H 'Content-Type: application/json' \
-d '{
"DestinationRealm": "epc.mnc001.mcc001.3gppnetwork.org",
"DestinationHost": "mme01",
"cancellationType": 2,
"diameterPeer": "mme01.epc...",
"immediateReattach": true
}'cancellationType follows 3GPP TS 29.272 §7.3.24.
The API is plain HTTP + JSON, so the standard requests library is all you need.
A complete, runnable set of examples lives in
tests/test_API.py.
import requests
BASE_URL = "http://hssip:8080"
# Only needed when hss.lock_provisioning is True:
HEADERS = {
"Content-Type": "application/json",
# "Provisioning-Key": "changeThisKeyInProduction",
}
def create(path, body):
r = requests.put(f"{BASE_URL}{path}", json=body, headers=HEADERS)
r.raise_for_status()
return r.json()
# 1. SIM auth data
auc = create("/auc/", {
"ki": "465B5CE8B199B49FAA5F0A2EE238A6BC",
"opc": "E8ED289DEBA952E4283B54E88E6183CA",
"amf": "8000",
"sqn": 0,
})
# 2. APN
apn = create("/apn/", {
"apn": "internet",
"apn_ambr_dl": 9999999,
"apn_ambr_ul": 9999999,
"qci": 9,
"arp_priority": 1,
"arp_preemption_capability": True,
"arp_preemption_vulnerability": False,
})
# 3. Subscriber, referencing the IDs created above
subscriber = create("/subscriber/", {
"imsi": "001010000000001",
"enabled": True,
"auc_id": auc["auc_id"],
"default_apn": apn["apn_id"],
"apn_list": str(apn["apn_id"]),
"apn_list_swx": str(apn["apn_id"]),
"msisdn": "491792021244",
"ue_ambr_dl": 9999999,
"ue_ambr_ul": 9999999,
"nam": 0,
"subscribed_rau_tau_timer": 600,
})
# Read it back by IMSI
print(requests.get(f"{BASE_URL}/subscriber/imsi/001010000000001").json())- Generate a typed client from
/swagger.jsonfor larger integrations. - Capture the IDs returned by create (
PUT) calls — downstream objects reference them (e.g. a subscriber referencesauc_idand APN IDs). - Group related writes with the same
?operation_id=...so they can be rolled back together if a batch fails. - Use
GET /oam/pingas a readiness/liveness probe.
