The Catappult Developer Hub

Welcome to the Catappult developer hub. You'll find comprehensive guides and documentation to help you start working with Catappult as quickly as possible, as well as support if you get stuck. Let's jump right in!

Get Started    

One Step Payment

Overview

One Step Payment(OSP) is the simplest way to start an AppCoins purchase. It’s done by creating a simple URL with payment information, to check by yourself how simple it is, visit this page.

One Step Payment flow

  1. Create an URL to start the purchase flow. The URL should follow the documentation found here. Feel free to check our online tool to check how simple it is.
  2. The developer has to make a simple system call with the URL created at step 1.
  3. AppCoins wallet will communicate with our services to process the payment
  4. Once the purchase is over, our server will notify the app’s services with all the details about it.
  5. App’s server should deliver the purchased item.

🚧

Note: Make sure you set the Callback URL field so our servers can notify yours once the purchase is completed.

Create URL (1)

Create an URL with the following structure:
Scheme: https
Host: apichain.catappult.io
Path: /transaction/inapp
Query string arguments: value, currency, to, product, domain, data, callback_url, reference, signature
Example:

https://apichain.catappult.io/transaction/inapp?value=11&currency=usd&domain=com.appcoins.trivialdrivesample&product=sword.001

🚧

Warning!

Previously there was a "to" argument where the destination wallet address would be specified. This argument is no longer needed and was removed from this example.

Query String Arguments details

Overview

Parameter

Type

Description_of_field

Static

Optional

Example

value*

Double

The value in APPC (AppCoins by default) of the transaction.

N

N

11.5

currency

String

The currency in which the value is sent, if no currency is sent it is considered APPC (AppCoins).

N

Y

USD or EUR

product*

String

The id of the item being bought.

Y

N

sword.001

domain*

String

The application id, also known as package name.

Y

N

com.appcoins.trivialdrivesample

data

String

Additional information to be sent if needed.

N

Y

Awesome Sword

callback_url

String

The developer's URL to be called after the transaction is completed.

N

Y

https://mygamestudio.co/appcoins?out_trade_no=1234

order_reference

String

Unique identifier of the transaction created by the developer. (Cannot be used for different purchases)

N

Y

XYZ98880032

signature

String

The Hexadecimal string of the signed URL in order to be validated. For more details see section Content Validation.

N

Y

49bc6dac9780acfe5419eb16e862cf096994c15f807313b04f5a6ccd7717e78e

* mandatory fields

URL call (2)

Inside the app/game, an intent with the URL should be opened either with the browser, useful when the AppCoins Wallet is not installed, or by the AppCoins Wallet. In some cases, the user chooses to open the URL with the browser when the AppCoins Wallet is already installed or even chooses the option to always open the URL with the browser.
So in order to avoid this problem, we suggested the use of the below sample to create the intent to trigger the One Step billing flow.

Intent intent = buildTargetIntent(url);
try {
    startActivityForResult(intent, RC_ONE_STEP);
} catch (Exception e) {
    e.printStackTrace();
}
/**
* This method generates the intent with the provided One Step URL to target the
* AppCoins Wallet.
* @param url The url that generated by following the One Step payment rules
* 
* @return The intent used to call the wallet 
*/
private Intent buildTargetIntent(String url) {
  Intent intent = new Intent(Intent.ACTION_VIEW);
  intent.setData(Uri.parse(url));

  // Check if there is an application that can process the AppCoins Billing
  // flow
  PackageManager packageManager = getApplicationContext().getPackageManager();
  List<ResolveInfo> appsList = packageManager
            .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
  for (ResolveInfo app : appsList) {
    if (app.activityInfo.packageName.equals("cm.aptoide.pt")) {
      // If there's aptoide installed always choose Aptoide as default to open 
      // url
      intent.setPackage(app.activityInfo.packageName);
      break;
    } else if (app.activityInfo.packageName.equals("com.appcoins.wallet")) {
      // If Aptoide is not installed and wallet is installed then choose Wallet
      // as default to open url
      intent.setPackage(app.activityInfo.packageName);
    }
  }
  return intent;
}

Payment Notification (4)

How can the developer be sure that the purchase is valid ?
If a callback url is provided by the developer, our purchase service triggers a notification when a purchase is completed. In order to use this service you must:

📘

You can check https://github.com/Aptoide/appcoins-server-validator for a fully working sample

Set the callback_url

The composition of the callback URL can contain as query string any parameter relevant to the transaction so that it can be handled on the developer's side. As an example, the following url beside the endpoint contains also a transaction id relevant to the developer. Checkout the Payment Notification section to know more.

https://www.mygamestudio.com/v1/appcoins_ipn.php?out_trade_no=2082389608326064

Prepare your server

Our service will call the provided callback_url using the following specification:

Overview

Method: Post
URL: The provided URL
Body: signature, transaction
Content type: Json
Response code: 200

❗️

Response code

It's important that your service return 200 as status code so we acknowledge you did receive the notification successfully.

Body example

{
  "signature": "62747e2bd871b38794edf8e7e27fc525f523be4955beeb2467ba8617d10ef1ff3c39eac5c75a52c8ebc0badefec32a84616f26ebc0213fa86604567c218b74931b",
  "transaction": "{\"uid\":\"2DtyvTOSShc1xT9C\",\"domain\":\"com.appcoins.trivialdrivesample\",\"product\":\"gas\",\"reference\":\"XYZ98880032\",\"status\":\"COMPLETED\",\"added\":\"2020-05-04T10:19:44+00:00\",\"modified\":\"2020-05-04T10:19:44+00:00\",\"price\":{\"currency\":\"APPC\",\"value\":\"1\",\"appc\":\"1\"}}"
}

Body structure

Details about parameters present at the root of the json object sent when calling callback_url:

Type

Name

Description

Schema

Example

Body

signature

(Deprecated)
Notification signature based on transaction parameter

string

0x7b87a3c4dd63bee43d4c88

Body

transaction

Transaction resource in json

string

Signature

Deprecated: This argument is no longer used

Transaction parameter fields

This parameter is a json structured string should be parsed to get the information about the purchase itself

Name

Description

Schema

Example

uid

Unique ID for transaction resource

string

2DtyvTOSShc1xT9C

domain

Package name

string

com.appcoins.trivialdrivesample

product

Product name (aka SKU)

string

sword.001

reference

Unique identifier of the transaction created by the developer.

string

XYZ98880032

status

Transaction status

string

COMPLETED or CANCELED or FAILED

added

Transaction added timestmap

string

2020-04-18T06:15:18+00:00

modified

Transaction modified timestmap

string

2020-04-18T07:17:19+00:00

price.appc

Transaction price in AppCoins

string

115

price.currency

Transaction price currency (used by user to perform the purchase)

string

USD, APPC, EUR, etc

price.value

Transaction price value

string

11.5

Verify data integrity

You can verify if that all the data sent in transaction parameter is indeed generated by Catappult platform using our transactions api:
Method: GET
Scheme: https
HOST: api.blockchainds.com
Path: /broker/8.20200101/transactions/{uid}
Ex:

https://api.blockchainds.com/broker/8.20200101/transactions/2DtyvTOSShc1xT9C

Response:

{
  "uid": "2DtyvTOSShc1xT9C",
  "domain": "com.appcoins.trivialdrivesample",
  "product": "gas",
  "wallet_from": "0xa43748bf498d7070d05d4fde042c51c780ce71b9",
  "country": "PT",
  "type": "INAPP_UNMANAGED",
  "reference": "XYZ98880032",
  "hash": "0x234e3c2407680ffe07d4f1bb7bc5c773085cd4ca723669a0473777ceeaabab95",
  "origin": "BDS",
  "status": "COMPLETED",
  "added": "2020-05-04T10:19:45+00:00",
  "modified": "2020-05-04T10:19:45+00:00",
  "gateway": {
    "name": "appcoins_credits"
  },
  "metadata": null,
  "price": {
    "currency": "APPC",
    "value": "1",
    "appc": "1"
  }
}

The data that you get from the transaction argument should be the equals to the data you get from transactions api call.
Here's an example of how you can do it:

<?php
require_once "vendor/autoload.php";
use GuzzleHttp\Client;
function is_valid($notification_transaction, $webservice_transaction) {
    return $notification_transaction->uid === $webservice_transaction->uid &&
        $notification_transaction->domain === $webservice_transaction->domain &&
        $notification_transaction->product === $webservice_transaction->product &&
        $notification_transaction->status === $webservice_transaction->status &&
        $notification_transaction->reference === $webservice_transaction->reference &&
        $notification_transaction->price->currency === $webservice_transaction->price->currency &&
        $notification_transaction->price->value === $webservice_transaction->price->value &&
        $notification_transaction->price->appc === $webservice_transaction->price->appc;
}
#notification you receive on your backend in callback_url service
$notification = '
  "signature": "62747e2bd871b38794edf8e7e27fc525f523be4955beeb2467ba8617d10ef1ff3c39eac5c75a52c8ebc0badefec32a84616f26ebc0213fa86604567c218b74931b",
  "transaction": "\\"uid\\":\\"2DtyvTOSShc1xT9C\\",\\"domain\\":\\"com.appcoins.trivialdrivesample\\",\\"product\\":\\"gas\\",\\"status\\":\\"COMPLETED\\",\\"added\\":\\"2020-05-04T10:19:44+00:00\\",\\"modified\\":\\"2020-05-04T10:19:44+00:00\\",\\"price\\":\\"currency\\":\\"APPC\\",\\"value\\":\\"1\\",\\"appc\\":\\"1\\""
';
$notification_transaction = json_decode(json_decode($notification)->transaction);
$client = new Client();
$transaction_response = json_decode($client->get(
    'https://api.blockchainds.com/broker/8.20200101/transactions/'.$notification_transaction->uid
)->getBody());
var_dump(is_valid($notification_transaction, $transaction_response));
import json
import requests


def is_valid(notification_transaction, webservice_transaction):
    return notification_transaction['uid'] == webservice_transaction['uid'] and \
           notification_transaction['domain'] == webservice_transaction['domain'] and \
           notification_transaction['product'] == webservice_transaction['product'] and \
           notification_transaction['status'] == webservice_transaction['status'] and \
           notification_transaction['reference'] == webservice_transaction['reference'] and \
           notification_transaction['price'] == webservice_transaction['price'] and \
           notification_transaction['price']['currency'] == webservice_transaction['price']['currency'] and \
           notification_transaction['price']['value'] == webservice_transaction['price']['value'] and \
           notification_transaction['price']['appc'] == webservice_transaction['price']['appc']


notification = """{
  "signature": "62747e2bd871b38794edf8e7e27fc525f523be4955beeb2467ba8617d10ef1ff3c39eac5c75a52c8ebc0badefec32a84616f26ebc0213fa86604567c218b74931b",
  "transaction": "{\\"uid\\":\\"2DtyvTOSShc1xT9C\\",\\"domain\\":\\"com.appcoins.trivialdrivesample\\",\\"product\\":\\"gas\\",\\"reference\\":\\"XYZ98880032\\",\\"status\\":\\"COMPLETED\\",\\"added\\":\\"2020-05-04T10:19:44+00:00\\",\\"modified\\":\\"2020-05-04T10:19:44+00:00\\",\\"price\\":{\\"currency\\":\\"APPC\\",\\"value\\":\\"1\\",\\"appc\\":\\"1\\"}}"
}"""

notification_transaction = json.loads(json.loads(notification)['transaction'])
transaction_response = requests.get(
    'https://api.blockchainds.com/broker/8.20200101/transactions/{}'.format(
        notification_transaction['uid'])).json()

print(is_valid(notification_transaction, transaction_response))

URL Content Validation (optional)

For extra security of the URL used to start the purchase, in order to validate if the URL content has not been tampered, the developer can include the signature parameter in the URL. The signature parameter is built as shown below, where the URL is signed using a HMAC function with the use of SHA256 algorithm.
The required secret key should be only available at a server level and should be shared between the developer and provider. This field is not mandatory for the URL to work.

<?php
 
function generate_url(): string
{
    $secret = 'foobar';
   
    $url = 'https://apichain.catappult.io/transaction/inapp?value=2.50&currency=APPC&to=0xab949343e6c369c6b17c7ae302c1debd4b7b61c3&product=gems.001&domain=com.mygamestudio.game&data=100+gems&callback_url=https%3A%2F%2Fwww.mygamestudio.com%2Fappcoins%3Fout_trade_no%3D1234&reference=XYZ98880032';
   
    $signature = hash_hmac('sha256', $url, $secret, false);
   
    return $url . '&signature=' . $signature;
}
 
echo generate_url();
 
?>

🚧

Avoid having the secret key in the APK and instead sign it server side. Having the secret key in the APK may compromise the security delivered with this step of the URL building, since it can be easily obtained by anyone that has access to APK.

Updated 2 months ago

One Step Payment


Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.