Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Overview

With this service, the calling apps can carry out account opening operations. Apps will forward details to OnePipe. Apps will supply details required to open an account on behalf of a customer. If authorisation details are required by a provider, apps will have to provide this. OnePipe will in turn forward to the provider’s dedicated implementation.

Info

Before you proceed: Please read this.

Commercial model

At agreed settlement cycles, the host will debit the configured beneficiary account of the app for the use of this API and share that fee with all participants. Fees will be determined by the provider.

Special configuration notes

  • OTP override: All providers of this service should implement OTP, but support the configuration of otp_override such that based on this configuration, they could be instructed to bypass the OTP requirement for an app.

  • SMS handler: All providers that need to do OTP validation can use the Send SMS and Send Email services on OnePipe to send their OTP.

Note

Special Note

This service allows providers to support a manual mode, where if the API call fails or the provider cannot do automated account creation, then the provider implementation should send an email to a configured email address (and cc support@onepipe.io) and in the body of the email, include all the necessary details to open the account. Basically, the payload passed to the Open Account request, should be sent by email to an admin to perform manual account opening. Then the API should respond with a temporary account number of the format TEMP{{transaction_ref}}. And a status of Processing.

This should be encapsulated in a provider setting to be called email_failover. Such that if this flag is true, the above logic then executes.

Settlement & fees model

...

Model

...

How it works

...

Invoice

...

General idea

Background and problem statement

Today at OnePipe, we create unique workflows within GRB that match a specific CX or use case. At times, these workflows call underlying OnePipe APIs, at times they don’t. But they typically achieve a “jobs-to-be-done” goal for the user. One of the challenges we have always grappled with is how at times these workflows seem to precede the actual OnePipe API. And then we try to (in retrospect) figure out how to make such a workflow become API-first afterwards. Examples are: Account upgrade, GroupMoni Pay4Me, Pay-to-App, etc.

Proposed solution

OneChapp (on which GRB is based) today has a public API with which any channel can invoke and execute intents by following a conversation flow.

  1. Send text to an endpoint

  2. Text is matched to an intent and a session is established

  3. Intent executes and sends back a response

  4. Process and present the response in the best way possible

  5. Go back to #1 till service/session is completed.

Now, imagine that we can expose this back & forth flow via the standard api.onepipe.io but present it as a “service” that a OnePipe App can simply call to leverage the logic that we have already encapsulated within the intent.

Gliffy
imageAttachmentIdatt2061565975
macroIdeb624183-c26e-4300-bdfa-1145723984e7
baseUrlhttps://onepipe.atlassian.net/wiki
nameGRB Intent as a service on OnePipe
diagramAttachmentIdatt2061565970
containerId2043576321
timestamp1657953720671

This way, the API caller never needs to get setup as a channel on OneChapp (or learn full details of OneChapp API), and we can feel free to create proper jobs-to-be-done as intents first and OnePipe apps can leverage this flow first while we figure out how to turn these into standard OnePipe services a bit more measuredly.

Other advantages:

  1. We can iterate (as we currently do) on CX and flows freely in GRB as more facts come to light based on usage

  2. We no longer need to overly constraint CX within GRB (because we want to match standard OnePipe API flow at execution time)

  3. We can now roll out new service bundles faster to any partner that wants reuse some of our logic. e.g. WeKurnect trying to enable pay4me in their platform (current pay4me logic is deep with non-OnePipe API elements)

Process flows

Sequence of calls

  1. App calls /transact with the right NO auth detailsProvider responds with WaitingForOTP or PendingValidation as may be required

  2. In the details object, app inserts the user’s message as text + a callback url

  3. Provider responds with PendingValidation and an action object corresponding to the message from the underlying intent (text, menu, buttons, attachments)

    1. Where the response is delayed: Provider responds via the callback url

  4. App calls /transact/validate to supply OTP if neededthe user’s choice/text

  5. Provider responds with any of the completion codes Successful or Failed if it has all it needs to finish off the intent. Otherwise go back to #3

  6. To query the status of a transaction, the app can call /transact/query

  7. Where the provider supports it, the app can call /transact/reverse to request a reversal (if supported)

Gliffy
imageAttachmentIdatt214040634
baseUrlhttps://onepipe.atlassian.net/wiki
macroId5c111e2f-045e-4c81-9b69-ca5cb8264163
nameOpen Account
diagramAttachmentIdatt204964130
containerId214007878
timestamp1583764581910

INTERFACE SPECIFICATION (APP → ONEPIPE)

...

Info

Before you proceed: Please read this.

INTERFACE SPECIFICATION (APP → ONEPIPE)

Info

For details on encryption using the Triple DES Algorithm, read this.

Request (

...

/transact)

Code Block
languagejson
{
    "request_ref": "{{request_ref}}",
    "request_type": "openbenefits_accountintent",
    "auth": {
        "type": null,
        "secure": null,
        "auth_provider": "BeeceptorBenefits",
    },
    "route_modetransaction": null{
    },     "transaction": {
        "mock"mock_mode": "live",
        "transaction_ref": "{{transaction_ref}}",
        "transaction_desc": "A random transaction",
        "transaction_ref_parent": null,
        "amount": 0,
        "customer": {
            "customer_ref": "{{customer_id}}",
            "firstname": "Uju",
            "surname": "Usmanu",
            "email": "ujuusmanu@gmail.com",
            "mobile_no": "234802343132"
        },
        "meta": {
            "a_key": "a_meta_value_1",
            "another_key": "a_meta_value_2"
        },
        "details": {
            "name_on_accountmessage": "Tobi Olajide",
            "middlename": "Remilekun"{{some kain text to trigger the intent or respond to a message}}",
            "dobcallback_url": "yyyy-MM-dd-HH-mm-ss",
            "gender": "M",{{a url to post the response to for long running proceses}}",
             "title": "Mr",
            "address_line_1": "23, Okon street, Ikeja",
            "address_line_2": "Ikeja",
            "city": "lagos",
            "state": "lagos",
            "country": "NG"
        }
    }
}

Response (when otp_override = false)

Code Block
languagejson
{
    "status": "PendingValidation",
    "message": "Please enter the OTP sent to 2348022****08",
    "data": // An array of {{message}} elements. Such that if a developer already knows the EXACT set of questions that will follow in order to complete an intent, they can preload it, the provider will hold on their behalf and forward to OneChapp as each response is received. USE CASE: Making it possible to have one-shot API calls. e.g. We can then have Appsolute built a single USSD string to trigger pay4me in one shot when its time for retailer self-service
            "subsequent_messages": [
                {
        "provider_response_code": "900T0",            "providerquestion": "BeeceptorOnepipe Benefits",
          "errors": null,         "erroranswer": null, "Opt in"
          "provider_response": null     }
}

Response (when otp_override = true)

Code Block
languagejson
{,
             "status": "Successful",  {
  "message": "Transaction processed successfully",     "data": {         "provider_response_codequestion": "00Please enter your BVN",
          "provider": "Beeceptor",         "errorsanswer": null,"{{ encrypted BVN }}"
     "error": null,         "provider_response": {
  },
          "reference":"263636363633777",      {
      "account_number": "2233305555",             "contract_codequestion": null,"Please enter your    date (YYYY-MM-DD) of birth",
      "account_reference": "48214462006092",             "account_nameanswer": "Akinkunmi Olunloye",{{ encrypted DOB }}"
               "currency_code": "NGN", },
             "customer_email": "akin@onepipe.io",  {
          "bank_name          "question": null,"do you want    to continue?",
      "bank_code": null,             "account_typeanswer": null, "yes"
               "status": "ACTIVE" },
            "created_on": "2020-04-05 23:08:01",    {
                    "metaquestion":{} "4-digit transaction pin",
           }     } }

Request (validate with otp)

Code Block
languagejson
{   "request_ref":answer": "{{request_refencrypted PIN}}",
    "request_type":"open_account", 	"auth": {         "secure": "{{encrypted_otp}}",
        "auth_provider": "Beeceptor"      }],
    "transaction": {       "client_id": "{{app_code of the app}}", //optional
            "transactionsender_refid": "70713093460718"{{customer_ref}}", //optional
    }
}

Acceptable values for auth.type

...

Type

...

Description

...

bvn

...

Specifies that encrypted value in auth.secure is a customer bvn. It can also be null.

...

null

...

To open this account, it can be done without a BVN

Breakdown of the details object

For this service, the details object will have the following:

...

Field

...

Type

...

Requirement

...

Description

...

otp_override

...

boolean

...

optional

...

Defaults to false. If set to true, request will not be validated by OTP.

...

middlename

...

string

...

optional

...

Middle name of the customer.

...

name_on_account

...

string

...

compulsory

...

The name that should be on the account.

...

dob

...

string

...

compulsory

...

Date string for date of birth

...

gender

...

string

...

compulsory

...

Gender of the customer. This can be set to either M or F

...

title

...

string

...

compulsory

...

Gender of the customer. This can be set to either Mr, Mrs, Ms

...

address_line_1

...

string

...

compulsory

...

Address of customer

...

address_line_2

...

string

...

optional

...

Address of customer

...

city

...

string

...

compulsory

...

City

...

state

...

string

...

compulsory

...

State

...

country

...

string

...

compulsory

...

        "channel": "OnePipe", //optional
        }
    }
}
Note

NOTE: Any sensitive information (such as BVN, DOB, PIN etc) that would be provided in the subsequent messages MUST be encrypted using the app’s secret key.

Info

A NOTE ON subsequent_messages: An arrangement such that if a developer already knows the EXACT set of questions that will follow in order to complete an intent, they can preload it, the provider will hold the array on their behalf and forward to OneChapp as each response is received from OneChapp. USE CASE: Making it possible to have one-shot API calls. e.g. We can then have Appsolute built a single USSD string to trigger pay4me in one shot when its time for retailer self-service. Or we can have someone call a single API to upgrade an account from level 1 to 3

Response

Text

Code Block
languagejson
{
    "status": "Successful | Failed | PendingValidation",
    "message": "{{The same value in provider_response.action.message}}",
    "data": {
        "provider_response_code": "00",
        "provider": "Benefits",
        "errors": null,
        "error": null,
        "provider_response": {
            "reference":"263636363633777",
            "action": {
                "recipientId": "2347083108908",
                "message": {
                    "type": "text",
                    "text": "How much do you need?"                
                },
            }
            "meta":{}
        }
    }
}

Menu

Code Block
languagejson
{
    "status": "Successful | Failed | PendingValidation",
    "message": "{{The same value in provider_response.action.message}}",
    "data": {
        "provider_response_code": "00",
        "provider": "Benefits",
        "errors": null,
        "error": null,
        "provider_response": {
            "reference":"263636363633777",
            "action": {
                "recipientId": "2347083108908",
                "message": {
                    "type": "menu",
                    "text": "Welcome, how can I help you today?",
                    "menu": [
                        {
                            "id": "1",
                            "item": "Account Statement"
                        },
                        {
                            "id": "2",
                            "item": "Ask A Question"
                        },
                        {
                            "id": "3",
                            "item": "Balance Enquiry"
                        },
                        {
                            "id": "4",
                            "item": "Bill Payment"
                        }
                    ]
                },
            }
            "meta":{}
        }
    }
}

Buttons

Code Block
languagejson
{
    "status": "Successful | Failed | PendingValidation",
    "message": "{{The same value in provider_response.action.message}}",
    "data": {
        "provider_response_code": "00",
        "provider": "Benefits",
        "errors": null,
        "error": null,
        "provider_response": {
            "reference":"263636363633777",
            "action": {
                "recipientId": "2347083108908",
                "message": {
                    "type": "buttons",
                    "text": "Choose a password:",
                    "buttons": [
                        {
                            "title": "Enter password",
                            "url": "https://f31ac10a.ngrok.io/u/eb087"
                        }
                    ]
                },
            }
            "meta":{}
        }
    }
}

Attachments

Code Block
languagejson
{
    "status": "Successful | Failed | PendingValidation",
    "message": "{{The same value in provider_response.action.message}}",
    "data": {
        "provider_response_code": "00",
        "provider": "Benefits",
        "errors": null,
        "error": null,
        "provider_response": {
            "reference":"263636363633777",
            "action": {
                "recipientId": "2347083108908",
                "message": {
                    "type": "attachments",
                    "text": "Hi user, here are some sample attachments.",
                    "attachments": [
                        {
                            "type": "pdf",
                            "url": "http://164.100.133.129:81/econtent/Uploads/Session3%20Classification%20of%20Car%20by%20Body%20Style.pdf"
                        },
                        {
                            "type": "image",
                            "url": "https://www.summerhilllandscapes.com/wp-content/uploads/2016/10/SFrances_160726_3934_A.jpg"
                        }
                    ]
                },
            }
            "meta":{}
        }
    }
}

Request (/validate)

Code Block
languagejson
{
  "request_ref":"{{request_ref}}", 
  "request_type":"benefits_intent",
	"auth": {
        "secure": "{{the encrypted message or selection from the user}}",
        "auth_provider": "Benefits" 
    },
    "transaction": {
        "transaction_ref": "70713093460718"
    }
}

Acceptable values for auth.type

Type

Description

null

Auth type always set to null (but we would setup the App’s OneChapp creds as extras variables?)

Possible status response codes

For this service, these are the possible responses a client can receive

Status

Meaning

Successful

Standard success code

Failed

Standard failure code

WaitingForOTP

To signify that this provider has requested an OTP from the customer and it should be supplied.code

PendingValidation

To signify that this provider needs some extra information to be provided. The response.message will contain the prompt.

INTERFACE SPECIFICATION (ONEPIPE → PROVIDER MICRO SERVICE)

...

Info

Request payload from OnePipe to the provider microservice comes encrypted, using the Triple DES Algorithm. See details.

Read this closely.

Special notes for OTP override

Whenever a request is to be validated by OTP, the provider microservice should first call the provider, store response info in the database, send an OTP to the phone number attached to the BVN, then respond with WaitingForOTP.
On the OTP validation phase, if user OTP is valid, provider should retrieve info from the database, then respond with a Successful response.
NB: Data should be erased from the DB.

...

Info

Request payload from OnePipe to the provider microservice comes encrypted, using the Triple DES Algorithm. See details.

Read this closely.

Settlement & fees model

We can choose to charge a small fee like N2 for each completed intent. But if a OnePipe API is used underneath, it will carry it’s own pricing logic.

Model

How it works

Invoice

The host client will invoice the calling app periodically for all calls to the endpoint.