Developer12 min read

One-Time Charging SDK (CaaS)

Charge a specific amount once, for a single purchase or unlock.

Code, endpoints and integration detail.

The One-Time Charging SDK, which Digimart also calls CaaS (Charging as a Service) or on-demand charging, takes a single payment of a specific amount from a subscriber's Grameenphone mobile account. Use it to unlock a feature, sell a ticket, or top up in-app credits.

This is not a REST API

You build a signed URL in your own application and open it. Digimart owns every screen until it returns the subscriber to your redirectUrl, then posts you the result server-to-server.

How it differs from a subscription

Two things change, and nothing else:

  • The path is /sdk/subscription/caas-authorize rather than /sdk/subscription/authorize.
  • There is an amount, and it is part of the signing string. This is the single most common reason a working subscription integration fails when it is copied across to one-time charging.

The amount is signed

The signing string is apiKey|requestTime|apiSecret|amount. If you sign only the first three values, every request comes back E1002 (Invalid Signature), because the amount must be encrypted under the signature.

What you can charge

A single transaction must fall between 1 and 600. Outside that range the platform returns E1330 (amount too low) or E1329 (amount too high). In practice your real ceiling is whatever credit subscribers keep on their phones, so E3009 (insufficient balance) is the failure you will see most often.

How to build the URL

  1. Collect your credentials

    The API Key and API Secret from your approved application. The API Secret only ever contributes to the hash; it never appears in the URL.
  2. Generate a unique 15-digit requestId

    Reusing one is rejected with E1005.
  3. Take the current time in UTC

    For example 2024-07-08T10:33:54.929Z, generated in the Asia/Dhaka timezone.
  4. Sign four values, including the amount

    Join apiKey, requestTime, apiSecret and amount with pipes, then hash with SHA-512.
  5. Assemble the query string and open it

    Send amount as a query parameter as well as signing it.

Building the signature

import { createHash } from "node:crypto";

const apiKey = process.env.DIGIMART_API_KEY;
const apiSecret = process.env.DIGIMART_API_SECRET;

const requestId = String(Date.now()).padEnd(15, "0").slice(0, 15);
const requestTime = new Date().toISOString();
const amount = "10";

// A one-time charge signs the amount too:
//   apiKey | requestTime | apiSecret | amount
const signature = createHash("sha512")
  .update(`${apiKey}|${requestTime}|${apiSecret}|${amount}`)
  .digest("hex");

const url = new URL(
  "https://user.digimart.store/sdk/subscription/caas-authorize"
);
url.search = new URLSearchParams({
  apiKey,
  requestId,
  requestTime,
  signature,
  amount,
  redirectUrl: "https://www.mywebsite.com",
}).toString();

res.redirect(url.toString());

The flow in full

SIGNED URL/sdk/subscription/caas-authorize

One-time charging (CaaS)

Also called on-demand charging. The shape is the same as a subscription, with two differences: a different path, and an amount that is both sent as a parameter and folded into the signature.

https://user.digimart.store/sdk/subscription/caas-authorize

Signing string

Join these values with pipes, with no spaces, then hash the result with SHA-512 and send the hex digest as the signature.

apiKey|requestTime|apiSecret|amount

The amount must be encrypted under the signature. Worked example from the tutorial: myApiKey123|2024-08-08T12:00:00Z|mySecretKey456|Amount, hashed with SHA-512.

Query parameters

Parameters for /sdk/subscription/caas-authorize
NameTypeRequiredDescription
apiKeysignedstringRequiredDisplayed on the application you created in the Digimart portal. Copy it after an administrator approves the app.
32c8a59cef446de3b78090d142ddac0e
requestIdstring (15 digits)RequiredA unique 15-digit identifier of your choosing. It correlates this request with the redirect response and the async notification. A requestId that has already been used cannot be reused for a new subscription.
123456789012345
requestTimesignedstring (UTC)RequiredThe current time in UTC format. Generate it in the Asia/Dhaka timezone (UTC+06:00): if you use a third-party library or a different zone, the value will not validate at our end.
2024-07-08T10:33:54.929Z
signaturestring (SHA-512 hex)RequiredSHA-512 hash of the pipe-joined string apiKey|requestTime|apiSecret|amount. The API Secret is never sent in the URL, only its contribution to this hash.
redirectUrlstring (URL)RequiredThe page subscribers are returned to after a successful or failed transaction, reached when they press 'Back to Application'.
https://www.mywebsite.com
msisdnstringOptionalThe subscriber's mobile number. Optional. If supplied, the number-entry screen is skipped and the flow goes straight to the OTP screen.
01748277168
amountsignednumberRequiredThe amount to be charged.
10

The URL you build

https://user.digimart.store/sdk/subscription/caas-authorize
  ?apiKey=32c8a59cef446de3b78090d142ddac0e
  &requestId=123456789012345
  &requestTime=2024-07-08T10:33:54.929Z
  &signature=0185e77e9cd469e0da58c6270eb838dc96af6e5c84f057405f3a62ea6979ac12491c47c69e0a42cab521b77b3b6409188304206c6308efa89c1971d0862ceda2
  &redirectUrl=https://www.mywebsite.com

What the subscriber sees

Digimart owns every screen below. You do not build any of them.

The subscriber enters their number and sees the exact amount before paying. Supplying msisdn skips this screen.
Step 3. The subscriber enters their number and sees the exact amount before paying. Supplying msisdn skips this screen.
Grameenphone generates and sends the OTP. The subscriber enters it here, with the charge restated.
Step 5. Grameenphone generates and sends the OTP. The subscriber enters it here, with the charge restated.
On a successful charge the subscriber sees a confirmation and an SMS is sent to their masked number.
Step 6. On a successful charge the subscriber sees a confirmation and an SMS is sent to their masked number.
If anything fails during the transaction journey, this error page is shown instead.
Step 7. If anything fails during the transaction journey, this error page is shown instead.

What comes back on the redirect

When the subscriber presses 'Back to Application' they are sent to your redirectUrl with these query parameters appended. This is a browser redirect, not a JSON body.

Redirect parameters for /sdk/subscription/caas-authorize
NameDescription
subscriptionStatusStatus code for the charge, either the success code or an error code.
S1000
subscriberIdMasked number corresponding to the subscriber.
requestIdThe initial request ID you allocated when the Charging SDK transaction was triggered.
123456789012346
http://user.digimart.store
  ?subscriptionStatus=S1000
  &subscriberId=ZjUyMTM1MjlhYmU0ZmJmY2FkYjRkYWI3NzE2ZDg0MjE0NjNjYTM5MGFhZTczOWZlZDUxMTcxN2U3YTVlZTRiNTpncmFtZWVucGhvbmU=
  &requestId=123456789012346

The async notification

Separately from the redirect, Digimart POSTs a JSON body to the endpoint you configured under 'Async charging resp URL' on your application. Treat this, not the redirect, as the record of the charge.

{
  "balanceDue": 0,
  "subscriberId": "ZjUyMTM1MjlhYmU0ZmJmY2FkYjRkYWI3NzE2ZDg0MjE0NjNjYTM5MGFhZTczOWZlZDUxMTcxN2U3YTVlZTRiNmU=",
  "statusDetail": "Request was Successfully processed, Due amount fully paid.",
  "version": "2.0",
  "timeStamp": "20240703090835",
  "totalAmount": "50.95",
  "requestId": "123456789012346",
  "currency": "BDT",
  "applicationId": "APP_000040",
  "internalTrxId": "924070309080000043",
  "paidAmount": "50.95",
  "statusCode": "S1000"
}

After the charge

As with subscriptions, the redirect is a convenience and the async notification is the record. Wait for statusCode: "S1000" on the notification before you hand over whatever the subscriber paid for, and reconcile it by requestId.

The notification carries totalAmount, paidAmount, balanceDue and internalTrxId. Compare paidAmount against what you asked for rather than assuming they match.