Purpose
This document provides implementation and configuration guidance for partners wishing to integrate their connectors with the NSPS using docker microservices. Please note that this document does not cover topics such as monitoring, high availability, disaster recovery, or other operational and infrastructure-related aspects. These areas are considered out of scope and are the responsibility of the solution architect overseeing the connector’s deployment and maintenance.
Overview
The primary goal of the NSPS is to automate the provisioning and service updates of external network systems (e.g., HLR, PCRF) triggered by changes within PortaBilling. This includes some similar tasks such as service activation, deactivation, and configuration updates. NSPS is aimed to provide an alternative and light-weight tool for cloud provisioning to cover some basic flows. If some fancy workflow logic is needed - it's worth to consider PortaOne Workflows solution instead.
The connector is a service that receives events enriched by NSPS from PortaBilling, selects the necessary parameters, and sends them to the external system in the format required by that external system.
The example provided in this document is designed to run in GCP or AWS. However, the new connector can run in any cloud (Azure, AWS, OCI, etc.) or on-premises, as it is designed as a Docker microservice.
- Hosting expenses for your connectors deployed in cloud platforms won't be covered by PortaOne.
- There is a local deployment options, at no extra costs, to consider:
- assuming test purposes or development - local PC/laptop
- assuming production but low traffic / load (otherwise, extra server(s) is required to handle the load): Docker Swarm managed via PortaBilling Portainer Stack
The interaction of the components is shown in the diagram below.
Implementation specific
Requirements
Authentication of all requests to the connector using a Bearer token.
Event payload schema parsing
Handling specific events (e.g., SIM activated, Plan changed, etc.)
- Configurable settings for External API server:
- API base URL with optional base path
- API access credentials (depends on the system implementation. This can be either Basic Auth, Bearer Auth with a static token, or support for example JWT. The connector should work with access_tokens and refresh_tokens if the system requires it)
- Response codes
- 2XX for a successfully processed event (with optional JSON response body)
- 4XX and 5XX codes for unsuccessfully processed events (with human-readable error explanation in response JSON body)
An example is available here - WTL HLR/HSS Connector.
The connector should provide 2 methods:
- GET health endpoint is needed to check the availability of the connector itself (this method should return just 200 OK with some optional response body).
- POST method is used by the NSPS system as a destination. The URL may or may not contain a path ( options such as "https://connector.com", "https://connector.com/api/events" are OK )
You can view or download an example of the OpenAPI specification below.
Request handling
The ESPF event generated by EventSender contains a limited set of variables (event type, i_account, i_env, etc.) but external systems usually require more information (about the main product, add-ons, used quotas, etc.).
Therefore, the NSPS system makes API requests to PortaBilling in order to get more information about the account, SIM, etc., which relates to the created event. The NSPS adds all the necessary data and passes it to the connector.Request body
NSPS sends the following request body to the connector (so the connector should accept it)
Field Name | Mandatory | Description |
---|---|---|
event_id | Yes | Unique identifier of the event. |
data | Yes | Event payload, represented by an instance of ESPFEvent . |
pb_data | No | Enriched data from PortaBilling; includes account, SIM, and access policy info. Defaults empty. |
handler_id | No | Optional identifier of the handler assigned to process the event. |
created_at | No | Timestamp when the event was created. |
updated_at | No | Timestamp when the event was last enriched by NSPS. |
status | No | Status of event processing. Defaults to EventStatus.UNDEFINED . |
The field called data
contains the generated ESPF event as it is. So if you don't need additional info from PortaBilling, you can only use this data.
The data structure for the pb_data
is shown below. It includes all possible fields. The connector should contain logic to process only the parameters it needs, and unnecessary ones can be ignored.
For a more detailed description of the parameters, please refer to docs.portaone.com
Field Path | Mandatory | Type | Description |
---|---|---|---|
pb_data.account_info | No | AccountInfo | Main account-level data container |
pb_data.account_info.bill_status | No | str | The billing status of the account. Mapped values (originally single-letter codes):
|
pb_data.account_info.billing_model | No | str | The account type. Mapped values (originally int codes):
|
pb_data.account_info.blocked | No | bool | Boolean conversion - Indicates whether account's calls and access to the self-care interface is blocked (originally Y/N string, converted Y → False, N → True) |
pb_data.account_info.email | No | str | The email address associated with the account |
pb_data.account_info.firstname | No | str | The account owner's first name |
pb_data.account_info.i_account | No | int | Internal ID of the account. Visible in URL resource path on Admin UI page |
pb_data.account_info.i_customer | No | int | The ID of the customer record to which the account belongs |
pb_data.account_info.i_master_account | No | int | The ID of the parent account |
pb_data.account_info.i_product | No | int | The ID for the account's product |
pb_data.account_info.i_vd_plan | No | int | The unique ID of the bundle assigned to the account individually |
pb_data.account_info.id | No | str | Charging ID (MSISDN, ICCID or IMSI) of the account on the network. Visible as ID in Admin UI |
pb_data.account_info.lastname | No | str | The account owner's last name |
pb_data.account_info.phone1 | No | str | The main phone number |
pb_data.account_info.product_name | No | str | The name of the account's product |
pb_data.account_info.status | No | str | The current status of the account based on factors such as "expiration time", "activation time" and so on.
|
pb_data.account_info.time_zone_name | No | str | The name of the account's time zone. The UI equivalent of this field is the 'Time zone' input field on the Edit Account → Personal info → General info → Web self-care panel. Examples: "Europe/Prague", "America/Vancouver", etc. |
pb_data.account_info.zip | No | str | The postal (zip) code |
pb_data.account_info.assigned_addons | No | List[AssignedAddon] | The list of the account's add-on products |
pb_data.account_info.assigned_addons[].addon_effective_from | No | str | ISO datetime string - The date and time when the add-on product is activated for an account (originally Optional[str] datetime) |
pb_data.account_info.assigned_addons[].addon_effective_to | No | str | ISO datetime string - The date and time when the add-on product assigned to an account expires (originally Optional[str] datetime) |
pb_data.account_info.assigned_addons[].addon_priority | No | int | The priority level of the add-on product |
pb_data.account_info.assigned_addons[].description | No | str | The internal product description |
pb_data.account_info.assigned_addons[].i_product | No | int | The unique ID of the product |
pb_data.account_info.assigned_addons[].i_product_group | No | int | The unique ID of the product group to which the product belongs |
pb_data.account_info.assigned_addons[].i_vd_plan | No | int | The unique ID of the bundle assigned to the product |
pb_data.account_info.assigned_addons[].name | No | str | The product name |
pb_data.account_info.service_features | No | List[ServiceFeature] | The list of service features |
pb_data.account_info.service_features[].name | No | str | The service feature name |
pb_data.account_info.service_features[].effective_flag_value | No | str | The actual service feature flag value. Possible values:
|
pb_data.account_info.service_features[].attributes | No | List[ServiceFeatureAttribute] | The list of service feature attributes |
pb_data.account_info.service_features[].attributes[].name | No | str | The service feature attribute internal name |
pb_data.account_info.service_features[].attributes[].effective_value | No | str | Service feature attribute value, comma-separated if multiple values |
pb_data.sim_info | No | SimInfo | SIM card information from PortaBilling |
pb_data.sim_info.i_account | No | int | The unique ID of the account to which the SIM card belongs |
pb_data.sim_info.i_sim_card | No | int | The unique ID of the SIM card |
pb_data.sim_info.iccid | No | str | The Integrated Circuit Card ID |
pb_data.sim_info.imsi | No | str | The unique International Mobile Subscriber Identity of the SIM card |
pb_data.sim_info.status | No | str | The status of the SIM card. Possible values:
|
pb_data.prev_sim_info | No | SimInfo | Previous SIM card information (used for SIM/Replaced events) |
pb_data.prev_sim_info.i_account | No | int | The unique ID of the account to which the SIM card belongs |
pb_data.prev_sim_info.i_sim_card | No | int | The unique ID of the SIM card |
pb_data.prev_sim_info.iccid | No | str | The Integrated Circuit Card ID |
pb_data.prev_sim_info.imsi | No | str | The unique International Mobile Subscriber Identity of the SIM card |
pb_data.prev_sim_info.msisdn | No | str | The Mobile Subscriber Integrated Services Digital Number |
pb_data.prev_sim_info.status | No | str | The status of the SIM card |
pb_data.access_policy_info | No | AccessPolicyInfo | Access policy information from PortaBilling |
pb_data.access_policy_info.i_access_policy | No | int | The unique ID of the Access Policy |
pb_data.access_policy_info.name | No | str | The name of the Access Policy |
pb_data.access_policy_info.attributes | No | List[AccessPolicyAttribute] | The list of related service policy attribute values |
pb_data.access_policy_info.attributes[].group_name | No | str | The name used to group service policy attributes |
pb_data.access_policy_info.attributes[].name | No | str | The name of the service policy attribute |
pb_data.access_policy_info.attributes[].value | No | str | Service policy attribute value, comma-separated if multiple values |
pb_data.product_info | No | ProductInfo | Product information from PortaBilling |
pb_data.product_info.name | No | str | The product name |
pb_data.product_info.description | No | str | The internal product description |
pb_data.product_info.i_product | No | int | The unique ID of the product |
pb_data.product_info.i_vd_plan | No | int | The unique ID of the bundle assigned to the product |
pb_data.product_info.addon_priority | No | int | The priority level of the add-on product.
|
pb_data.full_vd_counter_info | No | VDCounterInfo | VD counter information from PortaBilling |
pb_data.full_vd_counter_info[].discount_info | No | str | Short representation of the discount details (e.g., '0..60 - 100%') |
pb_data.full_vd_counter_info[].dg_name | No | str | The name of the destination group the bundle item is applied to |
pb_data.full_vd_counter_info[].i_vd_plan | No | int | The unique ID of the bundle |
pb_data.full_vd_counter_info[].i_dest_group | No | int | The unique ID of the destination group the discount is applied to |
pb_data.full_vd_counter_info[].allocated_amount | No | float | The total amount of service volume allocated to the customer/account in the current usage period |
pb_data.full_vd_counter_info[].unit | No | str | The name of the service unit or currency used |
pb_data.full_vd_counter_info[].addon_priority | No | int | The priority level of the bundle item. Possible values:
|
pb_data.full_vd_counter_info[].vdp_name | No | str | The name of the bundle |
pb_data.full_vd_counter_info[].i_vd_dg | No | int | The unique ID of the bundle item |
pb_data.full_vd_counter_info[].i_service | No | int | The unique ID of the service |
pb_data.full_vd_counter_info[].service_name | No | str | The name of the service the discount is applied to |
pb_data.full_vd_counter_info[].remaining | No | float /str | The service volume that remains to be used to reach the current threshold. Can be numeric value or string like 'N/A' |
Request headers
NSPS sends the following headers to the connector used for tracing and debugging:
The connector should process them and add them to all log messages related to the processing of a specific request. If the headers were not delivered, the connector should generate unique values (for example, use UUID-compatible format).
Event types
Event type | Trigger conditions | Most used fields |
---|---|---|
SIM/Updated |
|
|
SIM/Created | A SIM card has been added to the inventory. |
|
SIM/Deleted | A SIM card has been removed from the inventory. |
|
SIM/Replaced | A SIM card has been assigned to, removed from or changed for an account. |
|
Configuration
Typically, a connector should contain parameters that are needed to connect to the external system, as well as some that are needed by the application itself. The simplest and most straightforward option is to pass environment variables. The connector must verify all requests by checking the Bearer token. Therefore, there is a need to set this token in the connector. It is worth setting it as an environment variable (API_TOKEN for example) and reading it in the code. So, when changing only the environment variable, you can quickly change the access token in case of its compromise.
Requirements:
- configurable bearer token to access the service
- configurable external system credentials
Logging
Logging is an important part that allows debugging when necessary.
Requirements:
- Logs should be written in JSON format (for search integration)
- Log x-b3-traceid header to request_id field
- Log x-request-id header to unique_id field
Logging these headers allows you to track all the events that occur with the event from its very beginning - entering the NSPS.
Error handling
- Errors should be logged.
- Each error response must contain a JSON body with an explanation of the reason for the error.
Deployment
Since the connector is designed as a Docker microservice, it can be deployed in any cloud, for example, using a cloud-specific utility. Below are examples of scripts that you can use, but you can write your own that are simpler or more complex to suit your needs.
Example for GCP: deploy as a Cloud Run. Official guide on how to deploy Cloud Run services you can find here.
A Cloud Run service URL typically follows the format: https://[TAG---]SERVICE_IDENTIFIER.run.app
. SERVICE_IDENTIFIER
is a unique, stable identifier for the service, and the TAG refers to the traffic tag of the specific revision. The SERVICE_IDENTIFIER includes a random string and the region shortcut
https://[TAG---]SERVICE_NAME-PROJECT_NUMBER.REGION.run.app
where:
- TAG is the optional traffic tag for the revision that you are requesting.
- PROJECT_NUMBER is the Google Cloud project number.
- SERVICE_NAME is the name of the Cloud Run service.
- REGION is the name of the region, such as
us-central1
.
Example for AWS: deploy as an App Runner. Official guide on how to deploy App Runner services you can find here.
An App Runner service URL typically follows the format: https://[service-id].[region].awsapprunner.com
where service-id
is a unique identifier for your service and region is the AWS region where your service is hosted.
For example: https://abcd1234efgh.us-east-1.awsapprunner.com
Testing
You can test the application by sending an HTTP request.
First, you can make sure that the service is up and running by sending a health check request
Then you need to send a request with the expected data structure
What should be tested:
- Auth
- Response codes (2XX, 4XX, 5XX)
- Changes to the external system
It is worth testing this service with some kind of external staging system. It is not recommended to use production immediately without being sure that the service works correctly.
Infrastructure Considerations
The default deployment of NSPS, PortaBilling, and Connector/Core is intended to run in a public internet environment, where services can communicate freely over the network. However, in specific cases, it may be necessary to restrict public access to components for security reasons.
At this time, we can provide a static IP address used by NSPS to make requests to both the Connector and PortaBilling.
VPN connectivity is not currently supported and is under consideration (DO-5364).