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.