ocolin / billmax
A small REST API client for Billmax billing software
Requires
- php: ^8.3
- guzzlehttp/guzzle: 7.15.2 || ^8.0.1
- ocolin/global-type: ^2.0
Requires (Dev)
- ocolin/easyenv: ^3.0
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^13.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Table of Contents
- What is it?
- Requirements
- Installation
- Todo
- Configuration
- Getting your API Key
- Response
- Function Parameters
- Method Functions
- Request Method
- Filter
- Getting your API key
- Uploading
- Error handling
What is it?
This is a small lightweight PHP client for using the REST API service of Billmax billing software.
Requirements
- PHP ^8.3
- guzzlehttp/guzzle ^7.15.2 || ^8.0.1
- ocolin/global-type ^2.0
Installation
composer require ocolin/billmax
Todo
- Add OAuth2 support
- Add more integration testing
Configuration
Settings
The client can be configured by either environment variables, constructor arguments, or a combination of both, Here is a list of the settings needed for configuration.
| Environment | Constructor | Description |
|---|---|---|
| BILLMAX_API_KEY | $apiKey | API Key to access server |
| BILLMAX_API_HOST | $host | Hostname and URI of API server |
| BILLMAX_API_AUTH | $auth | Authentication mode |
| BILLMAX_API_USERNAME | $username | Username for USERPASS mode |
| BILLMAX_API_PASSWORD | $password | Password for USERPASS mode |
| BILLMAX_API_OAUTH2_CLIENT_ID | $clientId | Client ID for OAuth2 mode |
| BILLMAX_API_OAUTH2_CLIENT_SECRET | $clientSecret | Client secret for OAuth2 mode |
| BILLMAX_API_APP_ID | $appId | App ID found in Billmax |
| BILLMAX_API_DEVICE_ID | $deviceId | Optional Device ID |
| BILLMAX_API_APP_VERSION | $appVersion | Optional app version |
| BILLMAX_API_TOKEN_DIR | $tokenDir | Optional auth token directory. Path must be absolute.Recomment using storage_path() for Laravel and DIR elsewhere. |
Authentication mode.
The Billmax REST API has 3 authentication modes:
- NONE - Uses only the Billmax remote application session ID
- USERPASS - Uses session ID of a staff employee via username/password
- OAUTH2 - Uses OAuth2 to authenticate. Not yet supported by this client.
Configuring with Environment variables.
// Manually setting variables for demonstration $_ENV['BILLMAX_API_HOST'] = 'https://myhost.com:3100/api/billmaxCoreApi/v1/'; $_ENV['BILLMAX_API_KEY'] = 'GETTHISFROMSESSIONIDINREMOTEAPP'; $_ENV['BILLMAX_API_AUTH'] = 'USERPASS'; $_ENV['BILLMAX_API_USERNAME'] = 'staffmember'; $_ENV['BILLMAX_API_PASSWORD'] = 'staffmemberpassword'; $_ENV['BILLMAX_API_APP_ID'] = 'billmax-techapp'; $billmax = new Ocolin\BillMax\Billmax();
Configuring with constructor
The Billmax client uses a Config object class to hold settings. You can configure this by creating a Config object.
$config = new Ocolin\Billmax\Config( host: 'https://myhost.com:3100/api/billmaxCoreApi/v1/', apiKey: 'GETTHISFROMSESSIONIDINREMOTEAPP', auth: 'USERPASS', username: 'staffmember', password: 'staffmemberpassword', appId: 'billmax-techapp' ); $billmax = new \Ocolin\Billmax\Billmax( $config: $config );
Guzzle HTTP options.
This client uses Guzzle to handle HTTP calls and allows for extra options to be specified in the Config object.
$config = new Ocolin\Billmax\Config( options: [ 'timeout' => 30, 'verify' => true ] );
Response
The Billmax client will return a response object with the following properties:
| Property name | Type | Description |
|---|---|---|
| status | int | The HTTP status code (200,401, etc) |
| statusMessage | string | The HTTP status message |
| headers | array | HTTP response headers |
| body | object|array | HTTP response body, json decoded |
Function Parameters
| parameter | method | type | description |
|---|---|---|---|
| endpoint | ALL | string | Endpoint URI path. Any variable tokens will get replaced with matching kesy in query array/object |
| method | N/A | string | HTTP method to use in the request() method |
| query | ALL | array|object | URI path and query parameters. Keys that match {tokens} in URI will ne interpolated into the URI path |
| body | POST/PATCH | array|object | HTTP body in array or object format. |
| autoGet | PATCH | boolean | Automatically get the stored generation value of row to be updated in Billmax. If the generation value changed from the time you check to the time you patch, an error will be thrown |
Method functions
GET
$response = $billmax->get( endpoint: '/accounts/{id}', query: [ 'id' => 1234 ] );
POST
$response = $billmax->post( endpoint: '/aps', body: [ 'name' => 'AP name', 'description' => 'AP description', 'pop' => 'My POP', 'maximumDownloadRate' => 1000 'maximumUploadRate' => 1000, 'fccTechnologyCode' => 'Other Wireline', 'technology' => 'wireless' ] );
PATCH
$response = $billmax->patch( endpoint: '/aps/{id}', query: [ 'id' => 1234 ], body: [ 'name' => 'Updated AP name' ], autoGet: true // Defaults to true, but showing for example );
DELETE
$response = $billmax->delete( endpoint: '/aps/{id}', query: [ 'id' => 1234 ] );
Request method
Also included is a generic function without a specific HTTP method.
$response = $billmax->request( endpoint: '/aps/{id}', method: 'PATCH', query: [ 'id' => 1234 ], body: [ 'name' => 'updated name' ] );
Filter
The Billmax API has a query parameter that allows requests to be filtered. This class is to make creating filters easier by putting them in function calls rather than typing out a filter query.
A filter can have multiple conditions and each condiction consists of a field (a column in the database), an operator, and a value. The Filter allows these to be stacked together.
Condition format
Filter::where( name of columns )
->operatorFunction( value )
->build()
Filter::where( name of column1 )
->operator1( value )
->also( name of column2 )
->operator2( value )
->build()
Example
use Ocolin\Billmax\Filter; $output = $billmax->get( endpoint: '/accounts', query: [ 'fltrs' => Filter::where( 'id' ) ->in( [1,2,3] ) ->also( 'state' ) ->ne( 1 ) ->build() ] );
Condition functions
| Function name | Description |
|---|---|
| where | start condition |
| also | add additional condition |
| build | build the query into a string |
Operator functions
| Function name | Value type | Description |
|---|---|---|
| eq | string|int|float | equals |
| ne | string|int|float | not equals |
| like | string | like |
| nlike | string | not like |
| in | array | in [] |
| nin | array | not in [] |
| has | array | has [] |
| nhas | array | does not have [] |
| gt | string|int|float | greater than |
| lt | string|int|float | less than |
| gte | string|int|float | greater than or equal |
| lte | string|int|float | less than or equal |
| ft | string | fulltextindex - match against |
| ftb | string | fulltextindex - in boolean mode |
| ftq | string | fulltextindex - with query expansion |
Getting your API key.
The api ksy is part of your billmax remove application and was generated when you set up the remote application. Locating your API Key:
- Log into Billmax staff portal
- Under the System Administration menu, go to Remote Applications
- Click on the number next to your billmaxCoreApi app
- Copy the value from the Session Id field
- Click Generate Session Id if you want to create a new key.
Uploading
Because uploading files works much different from the rest of endpoints, a specific function as been created to handle file uploading. Note: Uploading will not re-try on failed authentication.
Upload arguments
| Argument | type | description |
|---|---|---|
| entity | string | Entity to attach file. Ex: account, ticket, message, service, etc. |
| entityId | integer | The ID of entity to attach to. Ex: account 1, ticket 3, service 1, etc. |
| filePaths | array | An array of file arrays. See table below for file path values. |
File Path Properties
Each file takes an array of values:
| Property Name | Type | Descrition |
|---|---|---|
| path | string | Path to and including the file to upload. |
| class | string | Billmax file class to use. Default is 'support' |
| description | string | A description of the file for display purposes |
Example
$output = $billmax->upload( entity: 'account', entityId: 1 files: [ [ 'path' => __DIR__ '/file.txt', 'class' => 'support', 'description' => 'My special file' ] ] );
Error handling
HTTP error statuses are returned, not thrown
A 4xx or 5xx response from the server is not an exception. It comes back as a normal Response object, so you decide what counts as a success for your use case. A 404 after a delete might be exactly what you wanted.
$response = $billmax->get( endpoint: '/accounts/{id}', query: [ 'id' => 999999 ] ); if( $response->status === 404 ) { // account does not exist }
The one exception is 401. If the server rejects the session, the client re-authenticates and retries the request once. If the retry is also rejected, an AuthException is thrown.
Exceptions
Everything the client throws at runtime extends one base class, so a single catch covers all of it.
| Exception | Thrown when |
|---|---|
BillmaxException |
Abstract base class. Catch this to handle everything below. |
ConfigException |
The request may not have reached the server (connection refused, DNS failure, timeout). Extends ApiException, so existing catch (ApiException) code still works. |
AuthException |
A login is rejected or fails, or a request is still unauthorized after re-authenticating. Triggers on a 400, 401 during authentication. |
ApiException |
The server answered but the response was unusable (not valid JSON), or a request was invalid (bad HTTP method, a PATCH with no generation value), or another transfer failure occurred. |
CacheException |
The token cache could not be read or written. |
All exceptions live in the Ocolin\Billmax\Exceptions namespace.
use Ocolin\Billmax\Exceptions\BillmaxException; try { $response = $billmax->get( endpoint: '/accounts/{id}', query: [ 'id' => 1234 ] ); } catch( BillmaxException $e ) { // anything the client can throw at runtime }
Telling an outage from a rejection
An unreachable server throws ConnectionException. A refused login throws AuthException. Catch the specific class first:
use Ocolin\Billmax\Exceptions\AuthException; use Ocolin\Billmax\Exceptions\BillmaxException; use Ocolin\Billmax\Exceptions\ConnectionException; try { $response = $billmax->get( endpoint: '/accounts' ); } catch( ConnectionException $e ) { // could not reach the server } catch( AuthException $e ) { // credentials rejected, send the user back to log in } catch( BillmaxException $e ) { // everything else }
ConnectionException means the request may not have reached the server. A timeout after the request was sent can still have been processed, so only retry operations that are safe to repeat (GET, DELETE). Be careful retrying a POST, which could create a duplicate.
The original Guzzle exception is available through getPrevious().