NAV
shell

Getting Started

Welcome to Taal development! You can use our APIs to access merchant API endpoints, which allows for the submission of Bitcoin transactions directly to our mining system.

We have examples written in Shell. You can view code examples in the area to the right, and you can switch the programming language of the examples with the tabs in the top right, where such examples exist.

Get an API key from TAAL

The following are the steps to get an API key from TAAL:

  1. Enter the URL https://www.taal.com/contact/ in your web browser.
    The Contact us page is displayed.

  2. Enter the required details and send your message to TAAL.

  3. The Commercial team will contact you to negotiate the terms.

  4. You will receive a transaction processing agreement from TAAL.

  5. Sign the transaction processing agreement and return it to TAAL.

  6. Enter the URL https://console.taal.com/register in your web browser.
    The TAAL Console register page is displayed.

  7. Register and log on to TAAL Console.

  8. In the Subscriptions tab, you can get a test net API Key and the main net API key for which you have subscribed.
    Suscriptions tab on TAAL Console

TAAL API (TAPI)

Overview

You can use TAAL API (TAPI) by:

In both the cases, you are issued with one or more API keys that you can retrieve on the TAAL Console .

You can use the TAPI to do the following:

TAAL service architecture

The following image describes the TAAL service architecture.

TAAL service architecture diagram

Merchant API (MAPI)

Overview

TAAL integrates the Merchant API (MAPI) reference implementation in its transaction processing architecture. MAPI enables the miners to submit the transactions.

Once you have subscribed to the TAAL Console, you can do the following using TAAL’s API (TAPI):

MAPI validates a transaction, and then sends it to the TAAL’s node for propagation to the network.

MAPI provides the API keys with specific settings for the transaction fees. For these specific fee settings, you can negotiate with TAAL directly or subscribe to the TAAL Console.

For more details, see the official Merchant API specification on Github. TAAL runs the official nChain MAPI implementation in production.

MAPI data flow

The following image describes the MAPI data flow.

MAPI data flow diagram

MAPI REST API interface

Register and log on to TAAL Console to use the following MAPI endpoints:

MAPI endpoints are available at:

To authorize, pass the header Authorization: Bearer <APIKey>, with issued from TAAL Console

Get policy quote

You can use the Get policy quote endpoint to get the different policies quoted by a miner. This endpoint returns a JavaScript Object Notation (JSON) envelope with a payload that contains the policies used by a specific BSV miner. The purpose of the JSON envelope is to ensure consistency in the message content to sign the responses. This endpoint is a superset of the fee quote service as it also includes information on DSNT IP addresses and miner policies.

The following is an example request for the Get policy quote endpoint:

curl  --header 'Authorization: Bearer <APIKey>' https://mapi.taal.com/mapi/policyQuote

The following is the JSON response to the above request:

{   
    "payload": "{\"apiVersion\":\"1.4.0\",\"timestamp\":\"2021-11-12T13:17:47.7498672Z\",\"expiryTime\":\"2021-11-12T13:27:47.7498672Z\",\"minerId\":\"030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e\",\"currentHighestBlockHash\":\"45628be2fe616167b7da399ab63455e60ffcf84147730f4af4affca90c7d437e\",\"currentHighestBlockHeight\":234,\"fees\":[{\"feeType\":\"standard\",\"miningFee\":{\"satoshis\":500,\"bytes\":1000},\"relayFee\":{\"satoshis\":250,\"bytes\":1000}},{\"feeType\":\"data\",\"miningFee\":{\"satoshis\":500,\"bytes\":1000},\"relayFee\":{\"satoshis\":250,\"bytes\":1000}}],\"callbacks\":[{\"ipAddress\":\"123.456.789.123\"}],\"policies\":{\"skipscriptflags\":[\"MINIMALDATA\",\"DERSIG\",\"NULLDUMMY\",\"DISCOURAGE_UPGRADABLE_NOPS\",\"CLEANSTACK\"],\"maxtxsizepolicy\":99999,\"datacarriersize\":100000,\"maxscriptsizepolicy\":100000,\"maxscriptnumlengthpolicy\":100000,\"maxstackmemoryusagepolicy\":10000000,\"limitancestorcount\":1000,\"limitcpfpgroupmemberscount\":10,\"acceptnonstdoutputs\":true,\"datacarrier\":true,\"dustrelayfee\":150,\"maxstdtxvalidationduration\":99,\"maxnonstdtxvalidationduration\":100,\"dustlimitfactor\":10}}",
    "signature": "30440220708e2e62a393f53c43d172bc1459b4daccf9cf23ff77cff923f09b2b49b94e0a022033792bee7bc3952f4b1bfbe9df6407086b5dbfc161df34fdee684dc97be72731",
    "publicKey": "030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e",
    "encoding": "UTF-8",
    "mimetype": "application/json"
}

The following table provides details of the response format for the Get policy quote endpoint.

Field Description
payload The main data payload encoded in a specific format type.
signature The signature on the payload string. It can be null.
publicKey The public key to verify the signature. It can be null.
encoding The type of encoding for the payload.
mimetype The type of Multipurpose Internet Mail Extensions (MIME) for the payload.

The following is the payload data of the JSON response:

{
    "apiVersion": "1.4.0",
    "timestamp": "2021-11-12T13:17:47.7498672Z",
    "expiryTime": "2021-11-12T13:27:47.7498672Z",
    "minerId": "030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e",
    "currentHighestBlockHash": "45628be2fe616167b7da399ab63455e60ffcf84147730f4af4affca90c7d437e",
    "currentHighestBlockHeight": 234,
    "fees": [
        {
            "feeType": "standard",
            "miningFee": {
                "satoshis": 500,
                "bytes": 1000
            },
            "relayFee": {
                "satoshis": 250,
                "bytes": 1000
            }
        },
        {
            "feeType": "data",
            "miningFee": {
                "satoshis": 500,
                "bytes": 1000
            },
            "relayFee": {
                "satoshis": 250,
                "bytes": 1000
            }
        }
    ],
    "callbacks": [
        {
            "ipAddress": "123.456.789.123"
        }
    ],
    "policies": {
        "skipscriptflags": [ "MINIMALDATA", "DERSIG", "NULLDUMMY", "DISCOURAGE_UPGRADABLE_NOPS", "CLEANSTACK" ],
        "maxtxsizepolicy": 99999,
        "datacarriersize": 100000,
        "maxscriptsizepolicy": 100000,
        "maxscriptnumlengthpolicy": 100000,
        "maxstackmemoryusagepolicy": 10000000,
        "limitancestorcount": 1000,
        "limitcpfpgroupmemberscount": 10,
        "acceptnonstdoutputs": true,
        "datacarrier": true,
        "dustrelayfee": 150,
        "maxstdtxvalidationduration": 99,
        "maxnonstdtxvalidationduration": 100,
        "dustlimitfactor": 10 
    }
}

The following table provides details of the payload format for the Get policy quote endpoint.

Field Description
apiVersion The version of the MAPI specification.
timestamp The timestamp of the payload document.
expiryTime The expiry time of the quote.
minerId The miner ID or the public key of miner. It can be null.
currentHighestBlockHash The hash of the current blockchain tip.
currentHighestBlockHeight The height of the current blockchain tip.
Fees The fees charged by the miner.
Callbacks The IP addresses of double-spend notification servers, such as MAPI reference implementation.
policies The values of miner policies as configured by the MAPI reference implementation administrator.

Get fee quote

You can use the Get fee quote endpoint to get the different fees quoted by a miner. This endpoint returns a JSON envelope with a payload that contains the fees charged by a specific BSV miner. The purpose of the JSON envelope is to ensure consistency in the message content to sign the responses.

The following is an example request for the Get fee quote endpoint:

curl  --header 'Authorization: Bearer <APIKey>' https://mapi.taal.com/mapi/feeQuote

The following is the JSON response to the above request:

{
    "payload": "{\"apiVersion\":\"1.2.0\",\"timestamp\":\"2020-11-12T13:17:47.7498672Z\",\"expiryTime\":\"2020-11-12T13:27:47.7498672Z\",\"minerId\":\"030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e\",\"currentHighestBlockHash\":\"45628be2fe616167b7da399ab63455e60ffcf84147730f4af4affca90c7d437e\",\"currentHighestBlockHeight\":234,\"fees\":[{\"feeType\":\"standard\",\"miningFee\":{\"satoshis\":500,\"bytes\":1000},\"relayFee\":{\"satoshis\":250,\"bytes\":1000}},{\"feeType\":\"data\",\"miningFee\":{\"satoshis\":500,\"bytes\":1000},\"relayFee\":{\"satoshis\":250,\"bytes\":1000}}]}",
    "signature": "30440220708e2e62a393f53c43d172bc1459b4daccf9cf23ff77cff923f09b2b49b94e0a022033792bee7bc3952f4b1bfbe9df6407086b5dbfc161df34fdee684dc97be72731",
    "publicKey": "030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e",
    "encoding": "UTF-8",
    "mimetype": "application/json"
}

The following table provides details of the response format for the Get fee quote endpoint.

Field Description
payload The main data payload encoded in a specific format type.
signature The signature on the payload string. It can be null.
publicKey The public key to verify the signature. It can be null.
encoding The type of encoding for the payload.
mimetype The type of MIME for the payload.

The following is the payload data of the JSON response:

{
    "apiVersion": "1.2.0",
    "timestamp": "2020-11-12T13:17:47.7498672Z",
    "expiryTime": "2020-11-12T13:27:47.7498672Z",
    "minerId": "030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e",
    "currentHighestBlockHash": "45628be2fe616167b7da399ab63455e60ffcf84147730f4af4affca90c7d437e",
    "currentHighestBlockHeight": 234,
    "fees": [
        {
            "feeType": "standard",
            "miningFee": {
                "satoshis": 500,
                "bytes": 1000
            },
            "relayFee": {
                "satoshis": 250,
                "bytes": 1000
            }
        },
        {
            "feeType": "data",
            "miningFee": {
                "satoshis": 500,
                "bytes": 1000
            },
            "relayFee": {
                "satoshis": 250,
                "bytes": 1000
            }
        }
    ]
}

The following table provides details of the payload format for the Get fee quote endpoint.

Field Description
apiVersion The version of the MAPI specification.
timestamp The timestamp of the payload document.
expiryTime The expiry time of the quote.
minerId The miner ID or the public key of miner. It can be null.
currentHighestBlockHash The hash of the current blockchain tip.
currentHighestBlockHeight The height of the current blockchain tip.
fees The fees charged by the miner.

Submit transaction

You can use the Submit transaction endpoint to send a raw transaction to a miner to include it in the next block, which the miner creates. This endpoint returns a JSON envelope with a payload that contains the response to the transaction submission. The purpose of the JSON envelope is to ensure consistency in the message content to sign the responses.

To submit transaction in the binary format use Content-Type: application/octet-stream with the binary serialized transaction in the request body. You can specify callbackUrl, callbackToken, merkleProof, dsCheck, and callbackEncryption in the query string.

When the Content-Type is application/octet-stream, it is possible to upload the transaction as a binary stream. For large transactions, the binary stream is half the size of the hexadecimal equivalent, however it is minimized using the gzip encoding of hexadecimal data.

The following is an example request for the Submit transaction endpoint:

curl --header "Content-Type: application/json" \
  --header 'Authorization: Bearer <APIKey>'
  --request POST \
  --data '...put json data here...' \
  https://mapi.taal.com/mapi/tx

The following is the response to the above request:

{
    "rawtx":        "[transaction_hex_string]",
    "callBackUrl":  "https://your.service.callback/endpoint",
    "callBackToken" : <channel token>,
    "merkleProof" : true,
    "dsCheck" : true,
    "callBackEncryption" : <parameter>
}

The following table provides the request details for the Submit transaction endpoint.

Field Description
rawtx The hex encoded for the transaction.
callbackURL The HTTP(S) endpoint used to receive messages from the miner.
callbackToken The HTTP authorization header used when authenticating against callbackURL.
merkleProof Requests a merkle proof.
dsCheck Requests the double-spend notification.
callbackEncryption The optional parameter to encrypt the callback data.

Notes:

The following is the content submitted on POST:

{
    "payload": "{\"apiVersion\":\"1.2.0\",\"timestamp\":\"2020-11-13T07:37:44.8783319Z\",\"txid\":\"fed22f5ab54202e2ec39cb745d427fcfff960254cde0cf283493ac545f5737f6\",\"returnResult\":\"success\",\"resultDescription\":\"\",\"minerId\":\"030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e\",\"currentHighestBlockHash\":\"39e3a2a0e7ba1b9e331cfd396cef1a2d3baffa51624af2f5512e530f35a8aa43\",\"currentHighestBlockHeight\":151,\"txSecondMempoolExpiry\":0}",
    "signature": "30440220160ff70b73297043a8ce9636f5abdc7d91918b4428e79876a405b080882d1c920220161b919399f50f16d8c9f922c13b94909d6e3a25480f09812c73f9ef52f8f542",
    "publicKey": "030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e",
    "encoding": "UTF-8",
    "mimetype": "application/json"
}

The following is the response to the above request:

{
    "apiVersion": "1.2.0",
    "timestamp": "2020-11-13T07:37:44.8783319Z",
    "txid": "fed22f5ab54202e2ec39cb745d427fcfff960254cde0cf283493ac545f5737f6",
    "returnResult": "success",
    "resultDescription": "",
    "minerId": "030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e",
    "currentHighestBlockHash": "39e3a2a0e7ba1b9e331cfd396cef1a2d3baffa51624af2f5512e530f35a8aa43",
    "currentHighestBlockHeight": 151,
    "txSecondMempoolExpiry": 0
}

The following table provides details of the request format for the Submit transaction endpoint.

Field Description
payload The main data payload encoded in a specific format type.
signature The signature on the payload string. It can be null.
publicKey The public key to verify the signature. It can be null.
encoding The type of encoding.
mimetype The type of MIME for the payload.

The following table provides details of the response format for the Submit transaction endpoint.

Field Description
apiVersion The version of the MAPI specification.
timestamp The timestamp of the payload document.
txid The ID of the transaction.
returnResult It contains success or failure of the transaction.
resultDescription It contains the error description on failure, and it is empty on success.
minerId The miner ID or the public key of miner. It can be null.
currentHighestBlockHash The hash of the current blockchain tip.
currentHighestBlockHeight The height of the current blockchain tip.
txSecondMempoolExpiry The duration (in minutes) for which transaction can be kept in the secondary mempool.
conflictedWith The list of all the double-spend transactions.

If a double-spend notification or Merkle proof is requested in the Submit transaction, the response is sent to the specified callbackURL. Where the recipients are using the Simplified Payment Verification (SPV) Channels, it requires the recipient to have a channel setup and ready to receive messages. For more details, see the Callback Notifications section.

Query transaction status

You can use the Query transaction status endpoint to check the status of a previously submitted transaction. This endpoint returns a JSON envelope with a payload that contains the transaction status. The purpose of the JSON envelope is to ensure consistency in the message content to sign the responses.

The following is an example request for the Query transaction status endpoint:

curl --header "Content-Type: application/json" \ --header 'Authorization: Bearer <APIKey>' https://mapi.taal.com/mapi/tx/{hash:[0-9a-fA-F]+}

The following is the JSON response to the above request:

{
    "payload": "{\"apiVersion\":\"1.2.0\",\"timestamp\":\"2020-11-13T07:53:59.580061Z\",\"txid\":\"76bb952edbdd649e92f5f74c0341f5afa8679629a7e36bda30f6d2d530ffef6f\",\"returnResult\":\"failure\",\"resultDescription\":\"Mixed results\",\"minerId\":\"030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e\",\"txSecondMempoolExpiry\":0}",
    "signature": "3044022038e82aff0decea8c95da0764c46e93613af2d5577468a89d0901de04f45fc83002205e073b1f5a8c275204873a6f14d5fa2d2acf5958f157201661d71fcbd57bbfe4",
    "publicKey": "030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e",
    "encoding": "UTF-8",
    "mimetype": "application/json"
}

The following table provides details of the request format for the Query transaction status endpoint.

Field Description
payload The main data payload encoded in a specific format type.
signature The signature on the payload string. It can be null.
publicKey The public key to verify the signature. It can be null.
encoding The type of encoding.
mimetype The type of MIME for the payload.

The following is the payload content:

{
    "apiVersion": "1.2.0",
    "timestamp": "2020-11-13T07:53:59.580061Z",
    "txid": "76bb952edbdd649e92f5f74c0341f5afa8679629a7e36bda30f6d2d530ffef6f",
    "returnResult": "failure",
    "resultDescription": "Mixed results",
    "minerId": "030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e",
    "txSecondMempoolExpiry": 0
}

The following is another possible return:

{
    "payload": "{\"apiVersion\":\"1.2.0\",\"timestamp\":\"2020-11-13T07:48:49.7666999Z\",\"txid\":\"6886cd04977d4cd26df3689b2d3c40b13685edb41fcc21c2962c5fc64560acff\",\"returnResult\":\"success\",\"blockHash\":\"236337115fef235a5d59cfcdf213cd70a86d6249a10eacf041468f15607094de\",\"blockHeight\":152,\"confirmations\":1,\"minerId\":\"030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e\",\"txSecondMempoolExpiry\":0}",
    "signature": "3044022039b759b4e80f13e1c91b40a42ac777704d3866b2f24432f57236b44fdfae13fe0220544a3853eb8d58f973a14dbec7e16c56a8242a8e68722102ed70de79a2b1455e",
    "publicKey": "030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e",
    "encoding": "UTF-8",
    "mimetype": "application/json"
}

The following is the payload, which is in the JSON response:

{
    "apiVersion": "1.2.0",
    "timestamp": "2020-11-13T07:48:49.7666999Z",
    "txid": "6886cd04977d4cd26df3689b2d3c40b13685edb41fcc21c2962c5fc64560acff",
    "returnResult": "success",
    "blockHash": "236337115fef235a5d59cfcdf213cd70a86d6249a10eacf041468f15607094de",
    "blockHeight": 152,
    "confirmations": 1,
    "minerId": "030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e",
    "txSecondMempoolExpiry": 0
}

The following table provides details of the payload format for the Query transaction status endpoint.

Field Description
apiVersion The version of the MAPI specification.
timestamp The timestamp of the payload document.
returnResult It contains success or failure of the transaction.
resultDescription It contains the error description on failure, and it is empty on success.
blockHash The hash of the transaction block.
blockHeight The height of transaction block.
minerId The miner ID or the public key of miner.
txSecondMempoolExpiry The duration (in minutes) for which transaction can be kept in the secondary mempool.

Submit multiple transactions

You can use the Submit multiple transactions endpoint to send the multiple raw transactions to a miner to include it in the next block, which the miner creates. This endpoint returns a JSON envelope with a payload that contains the responses to the transaction submissions. The purpose of the JSON envelope is to ensure consistency in the message content to sign the responses Submit multiple transaction.

You can omit callbackUrl, callbackToken, merkleProof, and dsCheck from the request body, and provide the default values in the query string.

The following is an example request for the Submit multiple transaction endpoint:

curl --header "Content-Type: application/json" \ --header 'Authorization: Bearer <APIKey>' --request POST \ --data '...put json data here...' \ https://mapi.taal.com/mapi/txs

The following is the request JSON POST content:

[
  {
    "rawTx": "01000000010136836d73f29cbe648bc2aeea20286502a3c2f2d3cff54522d0cc76bb755e9f000000006a4730440220533430d6f29d9437f94c60f0a59c857d254108fb9c375415fa53e9248d8bec5d0220606810830a6175dbee71da54fff6378a7aadfdb4b4714dc500cb3466ad4500004121027ae06a5b3fe1de495fa9d4e738e48810b8b06fa6c959a5305426f78f42b48f8cffffffff018c949800000000001976a91482932cf55b847ffa52832d2bbec2838f658f226788ac00000000",
    "callbackUrl":  "https://your.service.callback/endpoint",
    "callbackToken" : <channel token>,
    "merkleProof": true,
    "dsCheck": true,
    "callbackEncryption" : <parameter>
  },
  {
    "rawTx": "0100000001b753fbcb4e99659468067c2512b64d80c593bf46d4b60f750dd77c59391c4210000000006a473044022000cc88f3feadbacfd93e2a1a723e4fa4a20ef329ab5daac3be962d973bee3fb5022031642f58b5fce72e531f9dcae49e74be95cdb2f59a312865517fa536581d85584121027ae06a5b3fe1de495fa9d4e738e48810b8b06fa6c959a5305426f78f42b48f8cffffffff0198929800000000001976a91482932cf55b847ffa52832d2bbec2838f658f226788ac00000000",
    "callbackUrl":  "https://your.service.callback/endpoint",
    "callbackToken" : <channel token>,
    "merkleProof": true,
    "dsCheck": true,
    "callbackEncryption" : <parameter>
  }
]

The following table provides details of the payload format for the Submit multiple transactions endpoint.

Field Description
apiVersion The version of the MAPI specification.
timestamp The timestamp of the payload document.
minerId The miner ID or the public key of miner.
currentHighestBlockHash The hash of the current blockchain tip.
currentHighestBlockHeight The height of the current blockchain tip.
txSecondMempoolExpiry The duration (in minutes) for which transaction can be kept in the secondary mempool.
txs The list of the transaction responses.
txid The ID of the transaction.
resultDescription It contains the error description on failure, and it is empty on success.
returnResult It contains success or failure of the transaction.
failureCount The number of failed transaction submissions.

The following is the JSON response:

{
    "payload": "{\"apiVersion\":\"1.2.0\",\"timestamp\":\"2020-11-13T08:31:56.5722511Z\",\"minerId\":\"030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e\",\"currentHighestBlockHash\":\"08dc4bb006fc7e7186544343c3ccbb5a773d0a19cd2ccff1fa52f51eb6faf2ab\",\"currentHighestBlockHeight\":151,\"txSecondMempoolExpiry\":0,\"txs\":[{\"txid\":\"3145011f34a00d0666ea265b87c8e44108f87d3b53b853976906519ee8e1475f\",\"returnResult\":\"failure\",\"resultDescription\":\"Missing inputs\",\"conflictedWith\":[{\"txid\":\"86e1b384d3d169fd6aa4d34cf2d6f487436da54154befaab5a1fb25f844d65a8\",\"size\":191,\"hex\":\"01000000010136836d73f29cbe648bc2aeea20286502a3c2f2d3cff54522d0cc76bb755e9f000000006a4730440220761fb63128d4184fc142f2e854c499c52422db0136191f29f0bbe0969b6021770220536d72606d49dbbd244d2633b8b19031234138f045c530cc773e6e72bb34c62c4121027ae06a5b3fe1de495fa9d4e738e48810b8b06fa6c959a5305426f78f42b48f8cffffffff0198929800000000001976a91482932cf55b847ffa52832d2bbec2838f658f226788ac00000000\"}]},{\"txid\":\"c8a087b1ee775fa29697511ecd64e800941c8a22db6ed0989fb27a1d2d6798da\",\"returnResult\":\"success\",\"resultDescription\":\"\"}],\"failureCount\":1}",
    "signature": "304402200c4b0dc179906581eb32953abeddbef5799d302d82367aa9a469d79c15f932f3022029e827af6122290d5e1b80c50676b0336f4c7658ca67ba4819396dff9c6239a6",
    "publicKey": "030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e",
    "encoding": "UTF-8",
    "mimetype": "application/json"
}

The following is the payload content:

{
    "apiVersion": "1.2.0",
    "timestamp": "2020-11-13T08:31:56.5722511Z",
    "minerId": "030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e",
    "currentHighestBlockHash": "08dc4bb006fc7e7186544343c3ccbb5a773d0a19cd2ccff1fa52f51eb6faf2ab",
    "currentHighestBlockHeight": 151,
    "txSecondMempoolExpiry": 0,
    "txs": [
        {
            "txid": "3145011f34a00d0666ea265b87c8e44108f87d3b53b853976906519ee8e1475f",
            "returnResult": "failure",
            "resultDescription": "Missing inputs",
            "conflictedWith": [
                {
                    "txid": "86e1b384d3d169fd6aa4d34cf2d6f487436da54154befaab5a1fb25f844d65a8",
                    "size": 191,
                    "hex": "01000000010136836d73f29cbe648bc2aeea20286502a3c2f2d3cff54522d0cc76bb755e9f000000006a4730440220761fb63128d4184fc142f2e854c499c52422db0136191f29f0bbe0969b6021770220536d72606d49dbbd244d2633b8b19031234138f045c530cc773e6e72bb34c62c4121027ae06a5b3fe1de495fa9d4e738e48810b8b06fa6c959a5305426f78f42b48f8cffffffff0198929800000000001976a91482932cf55b847ffa52832d2bbec2838f658f226788ac00000000"
                }
            ]
        },
        {
            "txid": "c8a087b1ee775fa29697511ecd64e800941c8a22db6ed0989fb27a1d2d6798da",
            "returnResult": "success",
            "resultDescription": ""
        }
    ],
    "failureCount": 1
}

Callback notifications

Merchants can request callbacks for the Merkle proofs and/or double-spend notifications in the Submit transaction.

The URL for the double-spend example: POST /mapi/tx

When you submit a transaction and request the callback, the merchant should receive a notification of the Merkle proofs and/or double-spend through the callback URL. MAPI processes all the requested notifications and sends them in batches.

The callbacks have the following possible callbackReasons:

The DoubleSpendAttempt implies that the double-spend has been detected in the mempool.

The following is the request for the Merkle proof callback:

{
    "rawtx": "01000000015d7d8ffefc2b95a68a95d8e3c50715f8affc0e56ef58a05c773789e6fa3eb537010000006a47304402206c1ba36989bdca944c4ac1e74c23afaaf93fb6ded3a3d6e01f2c28667373c26e0220676085f6fe30071022ea5c8e790e7d9cf52671d0bc3c4d374991be65b6e11bc34121027ae06a5b3fe1de495fa9d4e738e48810b8b06fa6c959a5305426f78f42b48f8cffffffff018c949800000000001976a91482932cf55b847ffa52832d2bbec2838f658f226788ac00000000",
    "callbackUrl":"https://your-server/api/v1/channel/533",
    "callbackToken":"CNaecHA44nGNJCvvccx3TSxwb4F490574knnkf44S19W6cNmbumVa6k3ESQw",
    "merkleProof":false,
    "dsCheck": true
}

The following is the response body:

{
    "payload": "{\"apiVersion\":\"1.2.0\",\"timestamp\":\"2020-11-13T08:04:25.9291559Z\",\"txid\":\"0d0ad5677eb0862f94b3eda7f13633f91cf7c4c8c14e1451ffd333d52ff8e207\",\"returnResult\":\"failure\",\"resultDescription\":\"Missing inputs\",\"minerId\":\"030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e\",\"currentHighestBlockHash\":\"100677f99bdd7d4f0b8ea3f35d575d0f69a80f89b5b5f14e11005f57e5e63ef5\",\"currentHighestBlockHeight\":151,\"txSecondMempoolExpiry\":0,\"conflictedWith\":[{\"txid\":\"9f817649adde97338bcda695ee13ae1c71960eac60e49671fed0bdcf45581d94\",\"size\":191,\"hex\":\"01000000015d7d8ffefc2b95a68a95d8e3c50715f8affc0e56ef58a05c773789e6fa3eb537010000006a47304402206a9372778ff1ea314cfb2ec4e6bc93a57fe67c5ca915d004850f8079c876977c022066e3581cbec0eb2d525d4d83d01fff4f4e0b13a477f4f6a07d9168cc40bbabe54121027ae06a5b3fe1de495fa9d4e738e48810b8b06fa6c959a5305426f78f42b48f8cffffffff0198929800000000001976a91482932cf55b847ffa52832d2bbec2838f658f226788ac00000000\"}]}",
    "signature": "3044022048739a74a7f14b870d410f02c60dafcee2899348c7cd1184977e9ac5096ba63a022038ca0066645d1201ba0f385bd88da4c9bc7410582ae7bb3e248d79b7dbcfd205",
    "publicKey": "030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e",
    "encoding": "UTF-8",
    "mimetype": "application/json"
}

The following table provides details of the double-spend callback format for the Callback notifications endpoint.

Field Description
callbackPayload The payload with information about the new transaction.
apiVersion The version of the MAPI specification.
timestamp The timestamp of the payload document.
minerId The miner ID or the public key of miner.
blockHash The hash of the transaction block.
blockHeight The height of transaction block.
callbackTxId The transaction with the requested dsCheck.
callbackReason The reason for call back.
{
 "merkleProof": true
 "merkleFormat": "TSC"
}

The following is an example of the double-spend callback:

{   
    "callbackPayload": "{\"doubleSpendTxId\":\"f1f8d3de162f3558b97b052064ce1d0c45805490c210bdbc4d4f8b44cd0f143e\", \"payload\":\"01000000014979e6d8237d7579a19aa657a568a3db46a973f737c120dffd6a8ba9432fa3f6010000006a47304402205fc740f902ccdadc2c3323f0258895f597fb75f92b13d14dd034119bee96e5f302207fd0feb68812dfa4a8e281f9af3a5b341a6fe0d14ff27648ae58c9a8aacee7d94121027ae06a5b3fe1de495fa9d4e738e48810b8b06fa6c959a5305426f78f42b48f8cffffffff018c949800000000001976a91482932cf55b847ffa52832d2bbec2838f658f226788ac00000000\"}",
    "apiVersion": "1.4.0",
    "timestamp": "2021-11-03T13:24:31.233647Z",
    "minerId": "030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e",
    "blockHash": "34bbc00697512058cb040e1c7bbba5d03a2e94270093eb28114747430137f9b7",
    "blockHeight": 153,
    "callbackTxId": "8750e986a296d39262736ed8b8f8061c6dce1c262844e1ad674a3bc134772167",
    "callbackReason": "doubleSpend"
}

The following is an example of the double-spend attempt callback:

{   
  "callbackPayload": "{\"doubleSpendTxId\":\"7ea230b1610768374285150537323add313c1b9271b1b8110f5ddc629bf77f46\", \"payload\":\"0100000001e75284dc47cb0beae5ebc7041d04dd2c6d29644a000af67810aad48567e879a0000000006a47304402203d13c692142b4b50737141145795ccb5bb9f5f8505b2d9b5a35f2f838b11feb102201cee2f2fe33c3d592f5e990700861baf9605b3b0199142bbc69ae88d1a28fa964121027ae06a5b3fe1de495fa9d4e738e48810b8b06fa6c959a5305426f78f42b48f8cffffffff018c949800000000001976a91482932cf55b847ffa52832d2bbec2838f658f226788ac00000000\"}",
  "apiVersion": "1.2.0",
  "timestamp": "2020-11-03T13:24:31.233647Z",
  "minerId": "030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e",
  "blockHash": "34bbc00697512058cb040e1c7bbba5d03a2e94270093eb28114747430137f9b7",
  "blockHeight": 153,
  "callbackTxId": "8750e986a296d39262736ed8b8f8061c6dce1c262844e1ad674a3bc134772167",
  "callbackReason": "doubleSpendAttempt"
}

The following is an example of the Merkle proof callback:

{     
  "callbackPayload": "{\"flags\":2,\"index\":1,\"txOrId\":\"acad8d40b3a17117026ace82ef56d269283753d310ddaeabe7b5d226e8dbe973\",\"target\": {\"hash\":\"0e9a2af27919b30a066383d512d64d4569590f935007198dacad9824af643177\",\"confirmations\":1,\"height\":152,\"version\":536870912,\"versionHex\":"20000000",\"merkleroot\":\"0298acf415976238163cd82b9aab9826fb8fbfbbf438e55185a668d97bf721a8\",\"num_tx\":2,\"time\":1604409778,\"mediantime\":1604409777,\"nonce\":0,\"bits\":\"207fffff\",\"difficulty\":4.656542373906925E-10,\"chainwork\":\"0000000000000000000000000000000000000000000000000000000000000132\",\"previousblockhash\":\"62ae67b463764d045f4cbe54f1f7eb63ccf70d52647981ffdfde43ca4979a8ee\"},\"nodes\":[\"5b537f8fba7b4057971f7e904794c59913d9a9038e6900669d08c1cf0cc48133\"]}",
  "apiVersion":"1.2.0",
  "timestamp":"2020-11-03T13:22:42.1341243Z",
  "minerId":"030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e",
  "blockHash":"0e9a2af27919b30a066383d512d64d4569590f935007198dacad9824af643177",
  "blockHeight":152,
  "callbackTxId":"acad8d40b3a17117026ace82ef56d269283753d310ddaeabe7b5d226e8dbe973",
  "callbackReason":"merkleProof"
}

The following is an example of the TSC Merkle proof callback:

{
  "callbackPayload": "{\"index\":1,\"txOrId\":\"e7b3eefab33072e62283255f193ef5d22f26bbcfc0a80688fe2cc5178a32dda6\",\"targetType\":\"header\",\"target\":\"00000020a552fb757cf80b7341063e108884504212da2f1e1ce2ad9ffc3c6163955a27274b53d185c6b216d9f4f8831af1249d7b4b8c8ab16096cb49dda5e5fbd59517c775ba8b60ffff7f2000000000\",\"nodes\":[\"30361d1b60b8ca43d5cec3efc0a0c166d777ada0543ace64c4034fa25d253909\",\"e7aa15058daf38236965670467ade59f96cfc6ec6b7b8bb05c9a7ed6926b884d\",\"dad635ff856c81bdba518f82d224c048efd9aae2a045ad9abc74f2b18cde4322\",\"6f806a80720b0603d2ad3b6dfecc3801f42a2ea402789d8e2a77a6826b50303a\"]}",
  "apiVersion": "1.4.0",
  "timestamp": "2021-04-30T08:06:13.4129624Z",
  "minerId": "030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e",
  "blockHash": "2ad8af91739e9dc41ea155a9ab4b14ab88fe2a0934f14420139867babf5953c4",
  "blockHeight": 105,
  "callbackTxId": "e7b3eefab33072e62283255f193ef5d22f26bbcfc0a80688fe2cc5178a32dda6",
  "callbackReason": "merkleProof"
}

Use MAPI to send transactions

The following are the steps to send a transaction in MAPI:

  1. Enter the URL https://console.taal.com/login in your web browser.
    The TAAL Console login page is displayed.

  2. Log on to TAAL Console.

  3. Go to the Subscriptions tab and copy the API Key for which you want to send a transaction.

curl --header "Content-Type: application/json" \
  --header 'Authorization: Bearer <APIKey>'
  --request POST \
  --data '0100000001e75284dc47cb0beae5ebc7041d04dd2c6d29644a000af67810aad48567e879a0000000006a47304402203d13c692142b4b50737141145795ccb5bb9f5f8505b2d9b5a35f2f838b11feb102201cee2f2fe33c3d592f5e990700861baf9605b3b0199142bbc69ae88d1a28fa964121027ae06a5b3fe1de495fa9d4e738e48810b8b06fa6c959a5305426f78f42b48f8cffffffff018c949800000000001976a91482932cf55b847ffa52832d2bbec2838f658f226788ac00000000' \
  https://mapi.taal.com/mapi/tx

MAPI FAQs/Troubleshooting

Error message Troubleshooting
"Missing inputs - invalid output index" Check the wallet logic.
"Negative inputs are not allowed" Check the wallet logic.
Error fetching inputs" Check the wallet logic.
"Missing inputs" Check the wallet logic.
"tx rejected: missing inputs" Check the wallet logic.
"tx rejected: double spent" Check the wallet logic.
"Can not parse transaction" Check the UTXO.
"Transaction already in the mempool" Check the UTXO.
"Error while submitting transactions to the node Try again submitting the transactions after some time.
"evicted" This happens only if the mempool is full and does not contain P2P transactions. Try again the process after 1 hour.

TAAL Client

Overview

TAAL Client is a service that runs on the server of a TAAL customer and interacts with TAPI. You can use the TAAL Client to upload data onto the BSV Blockchain without the need to construct and fund raw transactions.

You can install and download the TAAL Client and obtain a valid TAAL API key. You can provide the data, and the TAAL component constructs a script stack to include the date (OP_Return) and finds the transaction (valid inputs) from the TAAL’s treasury. You can then sign the transaction and TAAL submits the signed transaction.

All the private keys used for signing a customer's transactions are held only on the customer's server.

The use of TAAL Client service is subject to fees as per the Transaction Agreement.

For more details, see the README.md on Github.

Notes:

Use cases

Register an API key

The following image describes the registration of the API key on the TAAL Client.

Register sequence

The following are the steps to register API Key on the TAAL Client:

  1. Enter the URL https://console.taal.com/login in your web browser.
    The TAAL Console login page is displayed.

  2. Log on to TAAL Console.

  3. Go to the Subscriptions tab and copy the API Key that you want to register.
    Tip: Ensure you have the TAAL Client installed on your system, or you can download and install from https://taal-gmbh.github.io/.

  4. Register the API Key in the TAAL Client by running the following command: taal-client register (APIKey).
    The API Key is registered on the TAAL Client, and you will see the success message: Registration successful.

Write data to the blockchain

Once you start the TAAL Client by running the command taal-client start, then you can write data to the blockchain by POSTing to the Taal Client.

Writing data

curl --location --request POST 'http://localhost:9500/api/v1/write' \
--header 'X-FeesRequired: true' \
--header 'X-Tag: AN_OPTIONAL_TAG' \
--header 'Authorization: Bearer <APIKey>' \
--header 'Content-Type: application/json' \
--data-raw '{
    "key1": "value1",
    "key2": "value2"
}

The following image describes the writing of data to the blockchain.

Writing sequence

The following are the steps to write the data to the blockchain:

  1. Enter the URL http://localhost:9500/taal-client/index.html in your web browser.
    The Simple WoC Client Example page is displayed.
    Simple WoC Client Example page

  2. In the Simple WoC Client Example page, do the following:
    a. In the API key field, enter the API Key.
    b. In the Enter text to send to blockchain box, enter the data you want to send to the blockchain.
    c. Click Send to blockchain.
    The data is written to the blockchain.

  3. You can use the following link to check the data you wrote on the blockchain:

https://test.whatsonchain.com/tx/f94347bea80c29d39f3e7e958a439ab7089ab0886f660aae26b2e7586f2abca6

STAS token library in Javascript

This library will create various types of STAS token transactions that add token functionality to the BSV blockchain.

The 6 STAS building functions are:

  1. Contract: This will create an OP_RETURN UTXO which contains a JSON schema that provides details about a particular token.
  2. Issue: This will spend the contract transaction and create a new P2STAS UTXO.
  3. Transfer: This spends a P2STAS UTXO and allocates it to a new destination P2STAS UTXO.
  4. Split: This spends a P2STAS UTXO and allocates it to 2 different P2STAS UTXOs.
  5. Merge: This merges 2 P2STAS inputs. Only available in Version 2. Can only merge if the in transactions have less than 3 outputs. (including the change)
  6. RedeemSplit: This spends a P2STAS UTXO and allocates some of the tokens to a standard P2PKH UTXO and the remainder to a destination P2STAS UTXO. The P2PKH destination must be the redemption public key hash.
  7. Redeem: This spends a P2STAS UTXO and creates a standard P2PKH of the full amount. The P2PKH destination must be the redemption public key hash.

Please note that the utils.js file is not needed to build STAS tokens: it contains tools to help interaction with Taal's private testing network, Taalnet.

Fees

The mining fee is set in the config.js file. The default is currently 500 sats per 1000 bytes which is 0.5 sats per byte. Change the sats to whatever you expect to pay.

Env Vars

The following environment variables must be set inside the .env file

API_USERNAME= The API username

API_PASSWORD= The API password

NETWORK= The netork that the tests will run on. 'livenet' is the main network

Testing

There is a file called lifecycle.test.js that exercises a full lifecycle of a STAS token. This file has limited testing.

npm install
node lifecycleV2.js

which will produce a series of transactions:

contract -> issue -> transfer -> split -> redeem split -> redeem.

There are various mocha tests located in test folder.
Files ending _tests contain multiple general tests per function (eg contract_tests.js contains contract tests) Files with specific names contain tests targeting a specific test case (eg mergeInvalidStasToken.js)

npm test  --  --grep 'Successful Merge With Fee'  // run specific test 
npm test .\test\merge_tests.js //run specific test file
npm test //run all tests
mocha --grep 'regression' --timeout 10000 // run all tests tagged with 'regression' 

All transactions are submitted to Taalnet, a private BSV blockchain that is maintained for testing STAS tokens. All tokens created can be viewed at https://taalnet.whatsonchain.com/tokens

Using in a browser

This library can be used within the browser, but only when configured correctly. stas-js is dependent on bsv.js which in turn is dependent on BN.js. BN.js assumes that Buffer exists globally as it does in NodeJS, however, this is not the case in the browser.

However, bsv.js is available as a standard JS library and it includes a copy of safe-buffer, which comes to the rescue. By adding this to our index.html, the Buffer polyfill is loaded for us.

Quick start with React

npx create-react-app myapp

cd myapp
npm install bsv@1 # very important to choose v1 of this library
npm install --from-git https://github.com/TAAL-GmbH/stas-js.git

cd public

Copy the file ../node_modules/bsv/bsv.min.js into the public folder add

<script src="%PUBLIC_URL%/bsv.min.js"></script>

to the end of the section in index.html.

cd ..

yarn start

Then you can replace the src/App.js with the following code:

import bsv from 'bsv'
import React, { useState } from 'react'

import './App.css'

import {
  contract,
  utils
} from 'stas-js'

const {
  getFundsFromFaucet,
  broadcast
} = utils

function App () {
  const privateKey = bsv.PrivateKey() // This will be a random privateKey each time the app is reloaded.
  const publicKeyHash = bsv.crypto.Hash.sha256ripemd160(privateKey.publicKey.toBuffer()).toString('hex')

  const [schema, setSchema] = useState(JSON.stringify({
    schemaId: 'Schema STAS Coupon',
    tokenName: 'TAALT',
    tokenId: publicKeyHash,
    tokenDescription: 'Example token on private Taalnet',
    issuerName: 'Taal Technologies SEZC',
    issuerCountry: 'CYM',
    issuerLegalForm: 'Limited Liability Public Company',
    issuerEmail: 'info@taal.com',
    issuerWebsite: 'https://taal.com',
    terms: '© 2020 TAAL TECHNOLOGIES SEZC\nALL RIGHTS RESERVED. ANY USE OF THIS SOFTWARE IS SUBJECT TO TERMS AND CONDITIONS OF LICENSE. USE OF THIS SOFTWARE WITHOUT LICENSE CONSTITUTES INFRINGEMENT OF INTELLECTUAL PROPERTY. FOR LICENSE DETAILS OF THE SOFTWARE, PLEASE REFER TO: www.taal.com/stas-token-license-agreement',
    governingLaw: 'Cayman Islands Law',
    icon: 'https://www.taal.com/wp-content/themes/taal_v2/img/favicon/favicon-96x96.png',
    tickerSymbol: 'TAALT'
  }, null, 2))

  function handleChange (event) {
    setSchema(event.target.value)
  };

  async function send () {
    try {
      const utxos = await getFundsFromFaucet(privateKey.toAddress('testnet').toString())

      const contractHex = contract(
        privateKey,
        utxos,
        JSON.parse(schema),
        10000
      )

      const contractTxid = await broadcast(contractHex)

      window.alert(`Your contract transaction id is ${contractTxid}`)
    } catch (err) {
      window.alert(`An error occurred: ${err}`)
    }
  }

  return (
    <div className='App'>
      <header className='App-header'>
        <label htmlFor='utxo'>Schema:</label>
        <textarea
          id='utxo'
          style={{ minHeight: 300, minWidth: 600 }}
          value={schema}
          onChange={handleChange}
        />

        <button onClick={send}>Send</button>
      </header>
    </div>
  )
}

export default App

Glossary

Blockchain

It is a form of distributed database (or ledger) that acts as a record of all the valid transactions which are transmitted to the blockchain network.

SPV Channels

Simplified Payment Verification (SPV) Channels are a set of JSON-over-HTTP public APIs for account holders and their counterparties to exchange messages in a secure manner.

UTXO

Unspent Transaction Output (UTXO) is an accounting method used in Bitcoin, and it refers to a balance of an BSV coin address that is controlled by a specific token.

Acronyms and Abbreviations

Acronym Abbreviation
API Application Programming Interface
BSV Bitcoin Satoshi Vision
gzip GNU zip
HTTP Hypertext Transfer Protocol
JSON JavaScript Object Notation
JWT JSON Web Token
MAPI Merchant API
MIME Multipurpose Internet Mail Extensions
P2P Peer-to-peer transactions
REST API Representational State Transfer API
SPV Simplified Payment Verification
TAPI TAAL API
TXID Transaction ID
USD United States dollar
UTXO Unspent Transaction Output