Engine API
Introduction
The engine API provides access to core engine methods of the OCS such as credit and debit methods which can be applied against the active wallet, or another wallet.
To access the API, require
the N2OCS engine API lua file:
local engine = require "n2.n2ocs.engine"
Types
.Unit
The Unit
type makes it convenient to refer to unit types in Lua through named
variables:
Field | Type | Description |
---|---|---|
.MICROCENTS | String | The string to use to refer to microcents (1,000,000 microcents in a cent) in the engine. |
.COUNTER | String | The string to use to refer to the general ‘counter’ type in the engine. |
.BYTES | String | The string to use to refer to bytes in the engine. |
.SECONDS | String | The string to use to refer to seconds in the engine. |
.FLAG | String | The string to use to refer to the flag bucket type in the engine. Flags cannot be used in rating. |
For example:
rating_requested = { {
unit = engine.Unit.COUNTER,
value = 1
} }
API Methods
.enquire
Perform an enquiry against the OCS rating engine. This checks to see if a subscriber can afford a debit without actually making changes to the subscriber wallet.
This method requires an enquiry_request
object provided to define
how the enquiry should proceed. This table of data is structured
as follows:
Field | Type | Description |
---|---|---|
.id |
String | [Optional] The ID to give to this enquiry request. While an enquiry request won’t generate EDRs, a debit request would and the id is the used in EDRs to uniquely identify the request. If an ID isn’t given, the system will generate a suitable one. |
.event_timestamp |
Timestamp | [Optional] The time to pretend it is when running the enquiry. This allows the system to run a request at a time different to the wall clock time. If the event_timestamp isn’t given, the system will use the current wall clock time. The date/time must be given in ISO8601 format. |
.rating_requested |
Array | [Required] A table of rating adjustments to attempt. |
.rating_context |
Table | [Optional] A table of data providing additional data for the rating request. What is required depends on the policies being run. |
The .rating_requested
array is an array of adjustments to attempt. Each
adjustment is a unit type and optional unit value.
rating_requested = { {
unit = -- unit type,
value = -- optional unit value
} }
Each rate table must include:
Field | Type | Description |
---|---|---|
.unit |
String | [Required] One of microcents , bytes , seconds , counter . It is recommended the type strings from the engine.Unit table are used. |
.value |
Number | [Optional] The value, either negative or positive, of the adjustment to make. This is in the JVM a long and supports up to 2^63-1 and down to -2^63. The value is optional and if not given the enquiry will either error, or if configured with appropriate policies, determine a quanta to attempt to rate. |
In this version of the OCS the enquiry request reflects 1:1 the debit request object as an enquiry is effectively a debit that does not get applied.
...
local engine = require "n2.n2ocs.engine"
-- An enquiry on a charge of $10
local request = {
rating_requested = { {
unit = engine.Unit.MICROCENTS,
value = 10 * 100 * 1000000
} }
}
local ok, resp = engine.enquire(request)
...
This method returns the enquiry response, which is the same in this version of the OCS as a rating response. See the debit method for details on this response.
On error, ok
will be set to false
and the error description will be
available in the second returned field.
.debit
Perform, if possible, a debit against a wallet in the OCS rating engine. This runs the full debiting engine against the wallet for the debit requested, with all appropriate policies.
This method requires the debit_request
object provided to define
what debit should be applied and all context information required to
correctly perform that debit. The content of the debit request
must conform to the following table:
Field | Type | Description |
---|---|---|
.id |
String | [Optional] The ID to give to this request. When the request generate an EDR the id is the used to uniquely identify the request. If an ID isn’t given, the system will generate a suitable one. |
.event_timestamp |
Timestamp | [Optional] The time to pretend it is when running the debit. This allows the system to run a request at a time different to the wall clock time. If the event_timestamp isn’t given, the system will use the current wall clock time. The date/time must be given in ISO8601 format. |
.rating_requested |
Array | [Required] A table of rating adjustments to attempt. |
.rating_context |
Table | [Optional] A table of data providing additional data for the rating request. What is required depends on the policies being run. |
The .rating_requested
array is an array of adjustments to attempt. Each
adjustment is a unit type and optional unit value.
rating_requested = { {
unit = -- unit type,
value = -- optional unit value
} }
Each rate table must include:
Field | Type | Description |
---|---|---|
.unit |
String | [Required] One of microcents , bytes , seconds , counter . It is recommended the type strings from the engine.Unit table are used. |
.value |
Number | [Optional] The value, either negative or positive, of the adjustment to make. This is in the JVM a long and supports up to 2^63-1 and down to -2^63. The value is optional and if not given the enquiry will either error, or if configured with appropriate policies, determine a quanta to attempt to rate. |
...
local engine = require "n2.n2ocs.engine"
-- A debit of $10
local request = {
rating = { {
unit = engine.Unit.MICROCENTS,
value = 10 * 100 * 1000000
} }
}
local ok, resp = engine.debit(request)
...
This method returns the debit response, as a debit_response
object, or on
error, ok
will be set to false
and the error description will be available
in the second returned field.
The debit response, if successful, will be a table of data giving information on the engine’s debiting process and the outcome of the request. The response will include the following fields:
Field | Type | Description |
---|---|---|
.request_id |
String | The ID of the request. Will be the same as the ID given in the debit request if one is given. |
.wallet_id |
String | The ID of the wallet against which the request was applied. |
.event_timestamp |
String | The ISO8601 formatted timestamp defining the time the rating event was applied to the wallet. |
.policies |
Array | Details on which engine policies were applied during rating. |
.costs |
Array | An array of adjustments applied and to which buckets the adjustment was applied. |
.funds_available |
Array | An array summarising the funds the wallet has, after the debit has been applied. This is a summary of the buckets the subscriber has. |
.rating_applied |
Array | An array summarising the charges per unit type applied to the wallet. Unlike the costs array, this one isn’t broken down by bucket ID. |
.starting_buckets |
Array | An array of the wallets buckets, before rating was applied. |
.ending_buckets |
Array | An array of the wallets buckets, after rating was applied. |
.final_unit_indicator |
Boolean | Set to false if the engine can determine that no further rating request of the same type can be applied to the wallet. Set to true if the engine believes it can rate the same debit again. Not included if this information cannot be determined. |
.ancillary_information |
Table | A table of data that gives more information on the debit result that is generated outside the core rating engine. |
.rating_applied
is an array of tables that include a unit
and value
. The
actual rating applied may of course not be the same as the rating requested
(due to unit conversions, discounts, or other policies).
.funds_available
is an array of unit/value data that reflects the
source request’s rating_requested
array. For each unit type present in
the source request’s rating_requested
array, the .funds_available
array will have an item. The value given by the funds_available
item
will be the total amount available of that unit, given the conversion
ratio applied during rating.
.costs
is similar to .rating_applied
, except that the costs lists each
bucket altered by the debit request. In addition to the value & unit, the
bucket ID is included:
Field | Type | Description |
---|---|---|
.unit |
String | The unit type of the bucket. |
.value |
Number | The decrease (or increase) adjustment amount made. |
.bucket_id |
String | The bucket ID of the bucket (which will appear in the .starting_buckets array. these funds were removed from. |
.source_unit |
String | If the rating engine charged this bucket based on rating requested in a different unit, the unit requested will be given by .source_unit . |
.source_value |
Number | If the rating engine charged this bucket based on rating requested in a different unit, the value of that requested unit and then charged against this specific bucket will be given by .source_value . |
The source_value
and source_unit
fields give insight into the conversion
applied by the rating requests.
.starting_buckets
is a snapshot of the buckets used for rating just before
the engine decided to rate. This is an array, since the engine order buckets
for use.
Note that not all buckets from the wallet are listed - only those buckets selected for rating are. Also, the order of the buckets reflects the order that the engine chose to use the buckets.
.ending_buckets
is the same bucket list as in .starting_buckets
, including
any expended buckets. This is the buckets immediately prior to
a commit against the wallet, and the removal of any zero-value buckets.
.policies
is an array of data tables describing the policies that
were used during the rating process.
.credit
Perform, if possible, a credit against a wallet in the OCS credit engine. This runs the engine processing for applying buckets to the wallet, with all appropriate policies.
Unlike a debit which is designed to apply generic unit adjustments, the credit method is designed to apply individual buckets to a wallet using bucket templates.
This method requires the credit_request
object provided to define
what credit should be applied and all context information required to
correctly perform that credit.
Field | Type | Description |
---|---|---|
.id |
String | [Optional] The ID to give to this credit request. The id is used in EDRs to uniquely identify the credit request. If an ID isn’t given, the system will generate a suitable one. |
.event_timestamp |
Timestamp | [Optional] The time to pretend it is when running the credit. This allows the system to run a request at a time different to the wall clock time. If the event_timestamp isn’t given, the system will use the current wall clock time. The date/time must be given in ISO8601 format. |
.credit_requested |
Array | [Required] A table of bucket templates to apply to the wallet. |
.credit_context |
Table | [Optional] A table of data providing additional data for the request. What is required depends on the policies being run. |
The .credit_requested
array is an array of buckets to add.
A bucket template has the following structure:
Field | Type | Description |
---|---|---|
.unit |
String | [Required] One of microcents , bytes , seconds , counter . It is recommended the type strings from the engine.Unit table are used. |
.value |
Number | [Required] The value, either negative or positive, of the bucket. This is in the JVM a long and supports up to 2^63-1 and down to -2^63. When giving credit the value of the bucket should always be defined (even if an “infinite value” bucket is being created). |
.expiry |
varies | [Optional] The expiry of a bucket can be given as an expiry object, or a ISO8601 formatted string. A bucket need not have an expiry. |
.annotations |
Array | [Optional] An array of objects defining annotations to give to the bucket on creation. |
An example of granting 1Gb to a subscriber:
...
local engine = require "n2.n2ocs.engine"
-- A credit of 1Gb
local request = {
credit = { {
unit = engine.Unit.BYTES,
value = 1024 * 1024 * 1024,
expiry = { months = 1 }
} }
}
local ok, resp = engine.credit(request)
...
When defining annotations in a bucket template, each annotation requires an annotation class and possibly some properties. E.g. to define a named bucket for a wallet:
bucket = {
unit = engine.Unit.FLAG,
value = 0x00f2,
annotations = {
{
annotationclass = "name",
properties = { name = "wallet-flags" }
}
}
}
Each annotation is a table defining the annotation. The following fields are expected for an annotation when defined on a bucket template:
Field | Type | Description |
---|---|---|
.annotationclass |
String | [Required] An annotation class name |
.properties |
Table | [Required] the properties for the annotation |
This method returns the credit response, as a credit_response
object, or on
error, ok
will be set to false
and the error description will be available
in the second returned field.
The credit response object contains details on the execution of the credit request. This includes the following fields:
Field | Type | Description |
---|---|---|
.request_id |
String | The ID of the request. Will be the same as the ID given in the credit request if one is given. |
.wallet_id |
String | The ID of the wallet against which the request was applied. |
.event_timestamp |
String | The ISO8601 formatted timestamp defining the time the rating event was applied to the wallet. |
.policies |
Array | Details on which engine policies were applied during rating. |
.starting_buckets |
Array | An array of the wallets buckets, before the credit was applied. |
.ending_buckets |
Array | An array of the wallets buckets, after the credit was applied. |
.affected_buckets |
Array | An array of the wallets buckets applied to the wallet. This will generally be a 1:1 copy of the bucket templates, with changes made to actualize the buckets. |
.transfer
Perform, if possible, a debit against an wallet and then within the same transaction a credit to another wallet - or to the same wallet.
This method combines the debit() and credit() requests into a single method call which acts atomically (with rollback of the debit) such that the debit is only performed if the credit succeeds.
Argument | Type | Description |
---|---|---|
credit_request |
Table | A credit request (see the .credit method details) |
debit_request |
Table | A debit request (see the .debit method details) |
This request works whether the wallet is the same on both requests, and in cases where one is different.
...
local ocs = require "n2.n2ocs"
local engine = require "n2.n2ocs.engine"
-- determine from executing context the wallet to credit
local target_wallet = "64210635462"
-- A transfer of 1Gb from our wallet to another wallet
local debit_request = {
rating = {
unit = engine.Unit.BYTES,
value = 1024 * 1024 * 1024
}
}
local credit_request = {
wallet = target_wallet,
credit = {
unit = engine.Unit.BYTES,
value = 1024 * 1024 * 1024
}
}
local ok, resp = context.transfer(debit_request, credit_request)
...
This method returns the credit response, as a credit_response
object, or on
error, ok
will be set to false
and the error description will be available
in the second returned field.
The debit response is dropped by the transfer()
method call, unless
the debit itself fails, in which case the debit error is returned and the
credit is not attempted.
The credit response document is detailed in the .credit method description.
.create_session
Create a session with a requested reservation of funds. Reservation of funds reserves the requested funds (or allows the OCS to calculate a valid reservation). The reservation may be given a unique ID, or one will be assigned.
Subsequently, not necessarily in the same Lua logic, the reservation can be committed or revoked.
Be aware of the validity time for the session itself. If a reservation is not committed or revoked within the timeframe (which could be derived from the rating engine’s core logic) then the session will be removed automatically.
A session request requires a session_request
object, which is
essentially a rating request wrapped by a reservation wrapper.
Field | Type | Description |
---|---|---|
.id |
String | [Optional] The ID to give to this request. This will be the ID of the session and used when the session is stored against the wallet. When the request generates EDRs for the session, this ID is used. If an ID isn’t given, the system will generate a suitable one. To commit or revoke a session the same session ID must be given. |
.event_timestamp |
Timestamp | [Optional] The time to pretend it is when creating and reserving the session. This allows the system to run a request at a time different to the wall clock time. If the event_timestamp isn’t given, the system will use the current wall clock time. The date/time must be given in ISO8601 format. |
.reservation |
Table | A rating_request object, as described by the .debit method. Note that unlike a debit, it is much more usual to not define exactly the value of the rating requested. |
An example of creating a session with a reservation is as follows:
...
local engine = require "n2.n2ocs.engine"
local session_request = {
reservation = {
rating_requested = {
unit = engine.Unit.BYTES
-- a value is not required for sessions. A session can
-- determine the amount to reserve based on reservation rules.
}
}
}
local ok, resp = engine.create_session(session_request)
if (ok) then
local session_id = resp.session_id
end
...
This method returns the session creation & initial reservation response. On
error, ok
will be set to false
and the error description will be available
in the second returned field.
The resulting response has the following structure:
Field | Type | Description |
---|---|---|
.session_id |
String | The session ID to use when committing/revoking this session. |
.event_timestamp |
String | The ISO8601 formatted timestamp defining the time the session was created on the wallet. |
.reservation |
Table | Details of the reservation granted. This is the equivalent of a debit response without the .costs list (since no actual charge has been applied), and the .rating_applied array is named .reserved_funds instead. |
.commit_session
Commit previously reserved funds within a session with optionally a new reservation of funds.
The commit request may declare the amount of funds to commit (i.e. debit) and should be within the reservation previously made (various policies might allow the commit to be higher than the reservation).
If a commit request does not declare the funds to commit, the whole previous reservation is committed.
As with session creation, reservation of funds reserves the requested funds (or allows the OCS to calculate a valid reservation). The new reservation continues to use the same session ID.
A session commit request requires a session_request
object with
a commit section and an optional reservation section to continue
the session (assuming the reservation succeeds)
Field | Type | Description |
---|---|---|
.id |
String | [Required] The session ID. This is used to determine the session on the wallet. |
.event_timestamp |
Timestamp | [Optional] The time to pretend it is when processing this request. |
.commit |
Table | [Optional] A rating_request object, as described by the .debit method that contains the actual amounts to debit. As this is a session commit, the amounts to commit should be equal or less than the amounts reserved (and be in the same units). However rating policies may allow some overuse of a commit in the right situations. |
.reservation |
Table | [Optional] A rating_request object, as described by the .debit method. A subsequent reservation to attempt, to keep the session open. |
Various fields of the .commit
and .reservation
sub-tables are
ignored during ongoing session commit/reserve cycles. For example
the rating_context
of the commit is always taken from the original
reservation, however the subsequent reservation (defined by the
.reservation
table) must redefine the rating context to use.
If a new .reservation
is not given on the session commit request,
the session is closed.
An example of creating a session with a reservation is as follows:
...
local engine = require "n2.n2ocs.engine"
local ok, session = engine.create_session(session_request)
if (not ok) then
return 405, session
else
local session_id = session.session_id
-- Perform some activity, such as a HTTP request
local commit_request = {
session_id = session.session_id
}
-- commit whole funds reserved
local ok, commit = engine.commit_session(commit_request)
if (not ok) then
-- clean up as best as you can
else
return 200
end
end
...
This method returns the session commit response, including the subsequent reservation details if another reservation was requested. Note that the commit can succeed and the following reservation may fail. This is not an error and the details of the commit response must be analysed to determine the validity of the reservation.
On a general error, ok
will be set to false
and the error description will
be available in the second returned field. A session response object for a
commit includes the following fields:
Field | Type | Description |
---|---|---|
.session_id |
String | The session ID of this session. |
.event_timestamp |
String | The ISO8601 formatted timestamp defining the time the commit occurred. |
.reservation |
Table | Details of the reservation granted, if one was requested. This is the equivalent of a debit response without the .costs list (since no actual charge has been applied), and the .rating_applied array is named .reserved_funds instead. |
.commit |
Table | Details of the reservation commit. This is the equivalent of a debit response without the .funds_available list. |
.revoke_session
Revoke previously reserved funds within a session. The revoke request will revoke all reserved funds and remove the session from the wallet.
...
local engine = require "n2.n2ocs.engine"
local ok, session = engine.create_session(session_request)
if (not ok) then
return 405, session
else
local session_id = session.session_id
-- Perform some activity, such as a HTTP request
local ok, resp = engine.revoke_session({session_id = session.session_id)
return 200
end
...
This method returns the session revocation response. Note that no additional
information is returned other than the success/failure flag/error string.
On a general error, ok
will be set to false
and the error description will
be available in the second returned field.
.subscribe_service
Perform a service subscription against an wallet. The following arguments are required to this method:
Field | Type | Description |
---|---|---|
service_name_or_id |
String | The name or ID of the service to subscribe to. |
subscription_context |
Table | A table of data that forms the subscription context to pass to the service. May be nil |
The subscription context is a table of data (which is subsequently converted to JSON) with context specific to the service being subscribed to. What is required or possible in this data object depends on how the service has been coded.
...
local engine = require "n2.n2ocs.engine"
-- subscribe to the prepaid $50 plan
local ok, resp = engine.subscribe ("PREPAID50")
if (not ok) then
-- handle error
end
The subscription details, including the subscription information itself, and
confirmation details on the service subscribed to are returned as the second
parameter on success. On failure, ok
is false, and the error string is
provided.
The subscription response object returned on success includes the following fields:
Field | Type | Description |
---|---|---|
.service |
String | The ID of the service subscribed to. This translates the name given in the request to the ID if required. |
.subscription |
Table | A table of data relating to the new subscription. |
The table of subscription data includes:
Field | Type | Description |
---|---|---|
.subscription_context |
Table | The subscription context. This will be the same as provided by the request, with additional details (if any) added by the subscription processing. |
.wallet_lifecycle_transition
Trigger a lifecycle event on the current wallet’s current wallet lifecycle using the event name. Note that the wallet’s lifecycle will need to have the event as a valid transition for this to work.
The following arguments are required to this method:
Field | Type | Description |
---|---|---|
event |
String | The event name to trigger. |
extra |
Table | A table of data that forms the context to pass to the lifecycle action triggered. May be nil |
The extra context is a table of data (which is subsequently converted to JSON) specific to the lifecycle event being triggered. What is required or possible in this data object depends on how the lifecycle has been developed.
This example lua script could be used as a hook to run on every wallet event within the OCS engine that attempts to reserve, debit or credit funds.
...
local engine = require "n2.n2ocs.engine"
local ocs = require "n2.n2ocs"
local wallet = ocs.context().active_wallet()
local lifecycle = wallet.lifecycle()
if (lifecycle ~= nil) then
local state = lifecycle.state()
if (state == "PREUSE") then
-- activate the wallet on pre-use trigger
local ok, resp = engine.wallet_lifecycle_transition ("activate")
if (not ok) then
-- handle error
end
end
end
This request returns true if the lifecycle transition succeeded and false (along with the error) if it did not.