API

From Open Transactions
Jump to navigation Jump to search

API Docs

The above two APIs are wrapped with SWIG, and thus available in many other languages.

The general rule of thumb is: When coding, always prefer the high-level API. Only use the low-level API for functions where no high-level API version is available. If you are writing software that uses OT, and you need to copy some sample code, just get it from the Moneychanger GUI.


NOTE: This page is old, but preserved in case of any usefulness.

Introduction

  • The opentxs list and opentxs help commands display a complete list of all the OT API functions available on the command line. The actual code for those commands, written using the OT high-level API, is available here for your perusal. This way, you can test the complete OT functionality at the command line, and then flip through the actual code for each command, and see how the OT API calls are used. You might be surprised how simple they really are.
  • With that as your guide, a general rule of thumb is this: Anytime you need to do something, use the high-level API to do it. Only if you can't find the function you are looking for, should you next resort to the low-level API. And remember, you can always the copy the code you need from the opentxs tool, or from the test GUI, otapiJ.

What does this mean for you? It means you no longer have to worry about synchronizing request numbers, or harvesting transaction numbers, or comparing inbox hashes, or downloading your nymbox, or dropped messages, or timeouts, or retries, etc! Instead, you use simple functions like send_transfer or withdraw_cash. The high-level API manages everything else behind the scenes.

The OT high-level API (OTMadeEasy) is now available in these languages: ChaiScript ( ot script ) and Java, CSharp, PHP, Python, D, Perl, and TCL. The low-level API is available in D, Python, PHP, Perl, Java, etc. (Via SWIG wrappers.)

USE CASES for the OT API

  • (Client software starts up.) Initialize the library and load the wallet.
  • Display for user: Server Contracts, Nyms, Accounts, and Asset Types.
  • Change the wallet's display label for any server, asset type, account, or nym.
  • Import a server contract (or asset contract) to the wallet.
  • Create a new Pseudonym (public/private key pair).
  • Register a public key (a "Nym") at an OT server.
  • Issue a new digital Asset Type. (Uploading an asset contract.)
  • Retrieve Currency Contract (by ID).
  • Create a new Asset Account.
  • Write a cheque (or invoice)
  • Send a Message to another user (via the server, encrypted to the recipient's public key.)
  • Deposit a cheque
  • Withdraw cash . . . . <==== CHAUMIAN DIGITAL CASH!!
  • Deposit cash
  • Withdraw Voucher
  • Account-to-Account Transfer
  • Create a new Basket Currency
  • Exchange Digital Assets in and out of Baskets (from your Asset Accounts)
  • Process your Inbox (Receipts and pending transfers)
  • Set up a Payment Plan
  • Issue a Market Offer

Initialize the library and Load your Wallet

(The user starts up the wallet software.)

Call OT_API_Init()

Then call OT_API_LoadWallet()


(NOTE: these above 2 steps are not necessary in OT-script, only Java and other languages.)

Display the current list of server contracts on the screen

Call OT_API_GetServerCount(), which returns the number of server contracts in your wallet.

For each one, call OT_API_GetServer_ID() to get the Server ID (which is a hash of the contract.)

Also for each, call OT_API_GetServer_Name() to get the Display Name from the contract.

In your GUI, display the name on the screen, but use the ID behind the scenes (for your messages to the server.)

Do the same thing for Nyms, Accounts, and Asset Types.

You can read about them on the API page, but here are the basic functions:

OT_API_GetNymCount(void);

OT_API_GetServerCount(void);

OT_API_GetAssetTypeCount(void);

OT_API_GetAccountCount(void);

OT_API_GetNym_ID() and OT_API_GetNym_Name()

OT_API_GetServer_ID() and OT_API_GetServer_Name()

OT_API_GetAssetType_ID() and OT_API_GetAssetType_Name()

OT_API_GetAccountWallet_ID() and OT_API_GetAccountWallet_Name()

Also:

OT_API_GetAccountWallet_Balance()

OT_API_GetAccountWallet_Type()

OT_API_GetAccountWallet_AssetTypeID()


Add a new server contract (or asset contract) to the wallet

Call OT_API_AddServerContract()

or OT_API_AddAssetContract().


Create a new Pseudonym

(Each user's wallet may contain many pseudonyms. Each Nym consists of a public and a private key, aka a "key pair".)

Call OT_API_CreateNym()

This creates a new key pair _("Nym")_ in your wallet, which you can use for communications with an OT server.

(That is, for opening asset accounts and performing various other transactions. A Nym is a "user account".)

(You can create as many of these pseudonyms as you want.)

(You can register the same nyms at multiple servers.)

(The same Nym will have the same Nym ID and public key on every server.)

Example

def details_create_nym(nKeybits, strName)
{
    var madeEasy = OT_ME()    
    var strNymID = madeEasy.create_pseudonym(nKeybits, "", "")  // returns new Nym ID
    
    if (!VerifyStringVal(strNymID))
    {
        OT_API_Output(0, "details_create_nym: Failed in OT_ME::create_pseudonym(keybits == " + nKeybits.to_string() + ")\n")
        return (0)
    }
    OT_API_Output(0, "Success creating! " + nKeybits.to_string() + " keybits, new ID: ") // stderr
    print(strNymID) // stdout
    OT_API_Output(0, "\n") //stderr
    // -------------------
    var bSetName = OT_API_SetNym_Name(strNymID, // subject
                                      strNymID, // signer
                                      strName)
    if (!bSetName)
    {
        OT_API_Output(0, "Failed in OT_API_SetNym_Name(name == " + strName + ")\n")
        return (0)
    }
    // -------------------    
    OT_API_Output(0, "Success setting name to: " + strName + "\n\n") // stderr
    return 1
}

Register a public key (aka "Nym") at an OT server

    var madeEasy	= OT_ME()
    if (VerifyExists("Server") && VerifyExists("MyNym"))
    {        
        var strResponse = madeEasy.register_nym(Server, MyNym)
        var nSuccess    = VerifyMessageSuccess(strResponse)
        switch(nSuccess)
        {
            case (1)
            {
                OT_API_Output(0, "\n\n SUCCESS in register_nym! Server response:\n\n");
                print(strResponse) // stdout
                break
            }
            default
            {
                OT_API_Output(0, "\n\n Failure or Error in register_nym!\n")
                
                if (VerifyStringVal(strResponse))
                {
                    OT_API_Output(0, "Server response:\n\n");
                    print(strResponse) // stdout
                }
                break
            }
        }

Change the wallet's label for any server/asset type/account/nym

(This is only a client-side label, for display purposes only.)

OT_API_SetNym_Name()

OT_API_SetAccountWallet_Name()

OT_API_SetAssetType_Name()

OT_API_SetServer_Name()


Issue a new digital Asset Type

User uploads a new currency contract to the server, so users can create asset accounts based on that asset type.

Server replies with a new issuer account ID (The new Issuer account appears inside your wallet's account list, so go ahead and iterate the list again, in order to display the updated list of accounts on the screen.)

High-level API version (in OT script):

        var madeEasy	= OT_ME()
        OT_API_Output(0, "Please paste a currency contract, followed by an EOF or a ~ by itself on a blank line:\n\n")
        var strContract = OT_CLI_ReadUntilEOF() 
        var strResponse	= madeEasy.issue_asset_type(Server, MyNym, strContract)
        var nStatus     = VerifyMessageSuccess(strResponse)
        
        switch(nStatus)
        {
            case (1)
            {
                OT_API_Output(0, "\n\n SUCCESS in issue_asset! Server response:\n\n");
                print(strResponse) // stdout
                break
            }
            default
            {
                OT_API_Output(0, "\n\n Failure or error in issue_asset. nStatus: "+nStatus.to_string()+"\n")
                if (VerifyStringVal(strResponse))
                {
                    OT_API_Output(0, "Server response:\n\n");
                    print(strResponse) // stdout
                }
                break
            }
        }

Retrieve Currency Contract (by ID)

User wants to download a currency contract from the server (for a given asset type ID.)

(The asset type ID is a hash of the contract, so OT will know if you get the wrong one, since this is verified whenever a contract is loaded up.)

High-level API version (in OT script):

    var madeEasy	= OT_ME()
    var strRetrieved   = madeEasy.retrieve_contract(Server, MyNym, strContractID)
    var nRetrieved     = VerifyMessageSuccess(strRetrieved)    
    var strSuccess = "ERROR"
    if (1 == nRetrieved)
    {   strSuccess = "SUCCESS" }
    else if (0 == nRetrieved)
    {   strSuccess = "FAILED" }
    OT_API_Output(0, "\n\n " + strSuccess + " retrieving contract: "+strContractID+"\n\n")

Create a new Asset Account

Example in OT Script, from the "sample scripts":https://github.com/FellowTraveler/Open-Transactions/tree/master/scripts/samples folder:

    def OT_ME::create_asset_acct(SERVER_ID, NYM_ID, ASSET_TYPE_ID) 
    {
        var ot_Msg := OTAPI_Func()
        // -------------------------
        var theRequest := OTAPI_Func(ot_Msg.CREATE_ASSET_ACCT, SERVER_ID, NYM_ID, ASSET_TYPE_ID)
        var     strResponse = theRequest.SendRequest(theRequest, "CREATE_ASSET_ACCT")
        
        return strResponse
    }

If it was a SUCCESS, then refresh the list of accounts in your display (from the OT API) since your new asset account should now be there.

(You can also use the "decode" command in the test wallet anytime you want to base64-decode something.)


TRANSACTIONS

FYI: Balance agreement, combined with transaction numbers, is what makes it possible for the server and all other parties to _eliminate account history, instead storing only the last signed receipt._ (Of course they have the choice to keep their own records--but they are no longer forced to do so.)

In order to do any transaction, the wallet's _balance agreement_ process requires that you have the latest copy of your account, inbox, and outbox files. You don't have to worry about this too much, since the high-level API will usually handle it for you.

You might ask: "But what if I download my account, or my outbox, and the server has maliciously inserted data into them?" No problem -- Open Transactions stores the last signed receipt from the server, and is able to verify the new intermediary files against that last receipt. You can see this happening when you run the command-line test client, and receipts can be verified programmatically using OT_API_VerifyAccountReceipt().

The Triple-Signed Receipts on Open Transactions ensure that this sort of protection is available to all parties, while simultaneously not having to store any transaction history!


Write a Cheque

Alice writes a cheque (offline): Call OT_API_WriteCheque()

Alice then gives cheque to Bob (offline), _or_ online if she prefers via OT_API_sendUserMessage() function.

If Alice has Bob's UserID but not his public key, her wallet first uses OT_API_checkUser() to retrieve his public key from the server, and then encrypts the cheque before sending it.

NOTE: a quality wallet software will keep track of ALL instruments! Even when Alice gives a cheque to Bob, her wallet should still store a copy of that cheque. Until when? Until at least after he has cashed it... when he does that, a chequeReceipt will appear in her inbox. Only when she accepts that receipt, signing a new balance agreement, is she finally free of the transaction number that was on that cheque. (It was still signed-out to her, all the way up until that time.)

WHAT IF Bob had never cashed it? WHAT IF he lost it? Is Alice supposed to just keep signing for that number forever? (The chequeReceipt will never appear in her inbox. She is doomed to continue signing for this number on all of her receipts on into the future, ad infinitum, with no hope of ever closing it out!)

Fear not, there is a solution: OT_API_DiscardCheque(). (Lucky you saved a copy of that cheque in your wallet, eh?) This function will retrieve Alice's transaction # back from the cheque, so that her wallet is free to use it on her next valid transaction, and then close it out normally.

Deposit a cheque

(A voucher is also a cheque, so you may deposit a voucher here the same as any other cheque.)

Bob sends message to server requesting deposit:

(High level API version, in Java.)

    public boolean depositCheque(String serverID, String nymID, String accountID, String cheque) {

        System.out.println("In depositCheque serverID:" + serverID + " nymID:" + nymID + " acount ID:" + accountID);

        // ---------------------------------------------------
        OTAPI_Func theRequest = new OTAPI_Func(OTAPI_Func.FT.DEPOSIT_CHEQUE, serverID, nymID, accountID, cheque);
        String strResponse = OTAPI_Func.SendTransaction(theRequest, "DEPOSIT_CHEQUE"); // <========================

        if (null == strResponse) {
            System.out.println("OTAPI_Func.SendTransaction() failed, in depositCheque.");
            return false;
        }
        // -------------------------------------------------------------------------------------- 

        return true;
    }

Withdraw cash

Alice's wallet first makes sure she has the latest public mint file, by calling OT_API_getMint().

(Note: if the mint she already has is within its valid date range, there's no need to do this.)

(Note: If she does call getMint, Alice needs to check the server reply and make sure it was successful before continuing with the withdrawal. The public mint keys are necessary for cash withdrawal.)

Alice then withdraws from her asset account, by messaging server: OT_API_notarizeWithdrawal()

Server replies with chaumian cash, which is stored in the purse folder in local storage.

Here is the full Java implementation of Withdraw Cash:

    public boolean withdrawCash(String serverID, String nymID, String accountID, String amount) 
    {
        String serverResponseMessage = null;
        System.out.println("In withdrawCash serverID:" + serverID + " nymID:" + nymID + " acount ID:" + accountID);
        String assetID = otapi.OT_API_GetAccountWallet_AssetTypeID(accountID);

        // ---------------------------------------- 
        // Make sure we have the proper asset contract for the withdrawal.
        //
        String assetContract = otapi.OT_API_LoadAssetContract(assetID);
        if (assetContract == null) {
            OTAPI_Func theRequest = new OTAPI_Func(OTAPI_Func.FT.GET_CONTRACT, serverID, nymID, assetID);
            String strResponse = OTAPI_Func.SendRequest(theRequest, "GET_CONTRACT");

            if (null == strResponse) {
                System.out.println("IN withdrawCash: OTAPI_Func.SendRequest(GET_CONTRACT) failed. (I give up.) (Unable to find asset contract.)");
                return false;
            }
            // ----------------------------------------
            assetContract = otapi.OT_API_LoadAssetContract(assetID);
            if (assetContract == null) {
                System.out.println("OT_API_LoadAssetContract returned null even after OT_API_getContract (Unable to find asset contract.)");
                return false;
            }
        }
        // ---------------------------------------------------------
        // Download the public mintfile if it's not there, or if it's expired.
        // Also load it up into memory as a string (just to make sure it works.)
        // Then we can actually send the withdrawal transaction request. (Until
        // then, why bother?)
        //
        String mintFile;

        // expired or missing.
        if (1 != otapi.OT_API_Mint_IsStillGood(serverID, assetID)) 
        {
            // ----------------------------------------
            OTAPI_Func theRequest = new OTAPI_Func(OTAPI_Func.FT.GET_MINT, serverID, nymID, assetID);
            String strResponse = OTAPI_Func.SendRequest(theRequest, "GET_MINT");

            if (null == strResponse) {
                System.out.println("IN withdrawCash: OTAPI_Func.SendRequest(GET_MINT) failed. (I give up.) (Unable to get mint.)");
                return false;
            }
            // ----------------------------------------
            mintFile = otapi.OT_API_LoadMint(serverID, assetID);
            if (mintFile == null) {
                System.out.println("OT_API_LoadMint returned null even after OT_API_getMint (I give up.) (Unable to find mint.)");
                return false;
            }
        }
        else // current mint IS available already on local storage (and not expired.)
        {
            mintFile = otapi.OT_API_LoadMint(serverID, assetID);
            if (mintFile == null) {
                System.out.println("OT_API_LoadMint returned null even after successful OT_API_Mint_IsStillGood (I give up.) (Unable to find mint.)");
                return false;
            }
        }        
        // ---------------------------------------------------
        // By this point, the mintfile is DEFINITELY good (available, not null, 
        // not expired, and loaded up.) Now we know for a fact that when the API
        // call is made to withdraw cash, that it will find the mint properly.
        //
        OTAPI_Func theRequest = new OTAPI_Func(OTAPI_Func.FT.WITHDRAW_CASH, serverID, nymID, accountID, amount);
        String strResponse = OTAPI_Func.SendTransaction(theRequest, "WITHDRAW_CASH"); // <========================

        if (null == strResponse) {
            System.out.println("OTAPI_Func.SendTransaction() failed, in withdrawCash.");
            return false;
        }
        // --------------------------------------------------------------------------------------

        return true;
    }

Deposit cash

Here is the complete Java implementation for Deposit Cash:

public boolean depositCash(String serverID, String nymID, String accountID, String purse, boolean isToken) {

        System.out.println("In depositCash serverID:" + serverID + " nymID:" + nymID + " acount ID:" + accountID + " isToken:" + isToken);
        Utility.setOtDepositCash(null);
        String oldPurse = purse;
        if (isToken) {
            purse = getNewPurse(purse, serverID, nymID, accountID);
            System.out.println("purse after getting from push purse:" + purse);
            if (purse == null) {
                Utility.setOtDepositCash(oldPurse);
                return false;
            }
        }
        // ----------------------------------------
        OTAPI_Func theRequest = new OTAPI_Func(OTAPI_Func.FT.DEPOSIT_CASH, serverID, nymID, accountID, purse);
        String strResponse = OTAPI_Func.SendTransaction(theRequest, "DEPOSIT_CASH"); // <========================

        if (null == strResponse) {
            System.out.println("IN depositCash: OTAPI_Func.SendTransaction(() failed. (I give up.) ");

            if (isToken) {
                System.out.println("IN depositCash, failed action for single token");
                String assetID = otapi.OT_API_GetAccountWallet_AssetTypeID(accountID);
                boolean importStatus = otapi.OT_API_Wallet_ImportPurse(serverID, assetID, nymID, purse) == 1 ? true : false;
                System.out.println("Since failure of depositCashPurse, OT_API_Wallet_ImportPurse called, status of import:" + importStatus);
                if (!importStatus) {
                    Utility.setOtDepositCash(purse);
                }
            }

            return false;
        }
        // ----------------------------------------
        return true;
    }

Note about local storage: Usually whenever something important is downloaded from the server, the OT API will save it automatically to the default storage context, and you can then load it up using another API call. This is usually the most convenient way to do things.



Account-to-Account Transfer

A _pending transfer_ will go into your outbox, and the recipient's inbox, pending acceptance by the recipient.

FYI, every asset account has its own inbox and outbox for handling pending transactions, as well as receipts.

FYI, every Nym similarly has its own Nymbox, used for receiving messages from other users, and for receiving new transaction numbers from the server.

Here is the OT Script implementation of Send Transfer, from the "sample scripts":https://github.com/FellowTraveler/Open-Transactions/tree/master/scripts/samples folder:

    def OT_ME::send_transfer(SERVER_ID, NYM_ID, ACCT_FROM, ACCT_TO, AMOUNT, NOTE) 
    {
        var ot_Msg := OTAPI_Func()
        // -------------------------
        var theRequest := OTAPI_Func(ot_Msg.SEND_TRANSFER, SERVER_ID, NYM_ID, ACCT_FROM, ACCT_TO, AMOUNT, NOTE)
        var     strResponse = theRequest.SendTransaction(theRequest, "SEND_TRANSFER")
        
        return strResponse
    }

Withdraw Voucher

A voucher is like a "money order" or "cashier's cheque". It's a cheque, but drawn on a server account, instead of your own account.

Withdrawing in voucher form is similar to withdrawing in cash: the server debits your asset account, and then gives you an official cheque.

But with cash, it's automatically saved to your purse, whereas with a voucher, you have to read the voucher out of the server reply, and display it on the screen!

Here is the complete Java code to perform Withdraw Voucher:

public String withdrawVoucher(String serverID, String nymID, String accountID, String amount, String chequeMemo, String recepientNymID) {

        System.out.println("In withdrawVoucher serverID:" + serverID + " nymID:" + nymID + " acount ID:" + accountID);

        // ---------------------------------------------------
        OTAPI_Func theRequest = new OTAPI_Func(OTAPI_Func.FT.WITHDRAW_VOUCHER, serverID, nymID, accountID, recepientNymID, chequeMemo, amount);
        String strResponse = OTAPI_Func.SendTransaction(theRequest, "WITHDRAW_VOUCHER"); // <========================

        if (null == strResponse) {
            System.out.println("OTAPI_Func.SendTransaction() failed, in withdrawVoucher.");
            return null;
        }
        // ---------------------------------------------------------
        String ledger = otapi.OT_API_Message_GetLedger(strResponse);
        if (ledger == null) {
            System.out.println(" ledger is null, returned by OT_API_Message_GetLedger, serverResponseMessage passed as argument");
            return null;
        }
        String transaction = otapi.OT_API_Ledger_GetTransactionByIndex(serverID, nymID, accountID, ledger, 0);
        if (transaction == null) {
            System.out.println("withdrawVoucher: transaction is null, returned by OT_API_Ledger_GetTransactionByIndex, argument passed, index 0 and ledger :" + ledger);
            return null;
        }
        // ---------------------------------------------------------
        String output = otapi.OT_API_Transaction_GetVoucher(serverID, nymID, accountID, transaction);
        System.out.println("output returned by OT_API_Transaction_GetVoucher:" + output);

        return output;
    }



BASKET CURRENCIES

Create a new Basket Currency

First, invent the basket in your head. Give it name: _"Clams."_

Next, give it a ratio in terms of other existing currencies: _"10 Clams equals a basket of 5 dollars, 3 Euro, and 20 Bitcoin"_

Call OT_API_GenerateBasketCreation() to begin creating the basket. The _"10 Clams"_ from above is set here.

Next, call OT_API_AddBasketCreationItem() for EACH currency in the basket. In the above example, I would call this function 3 times, in order to set the _"5 dollars"_ the _"3 Euro"_ and the _"20 Bitcoin"_ from above.

Now that the basket has been defined, call OT_API_issueBasket() to actually create the basket currency on the server.

(Now you have created a new asset type--a basket--which the server will control. Any user may now create accounts using this type! And from there, they can write cheques, withdraw cash, trade on markets, etc. the same as with any other asset type.)


Exchange Digital Assets in/out of a Basket Currency (from your Asset Accounts)

First, call OT_API_GenerateBasketExchange() to setup the exchange. You'll need to know the basket's asset type, and you'll need to have an existing asset account of that type. You will also set the "transfer multiple" in that call.

What's the transfer multiple? Remember the ratio above: "10 Clams equals a basket of 5 dollars, 3 Euro, and 20 Bitcoin"

Here are examples of the transfer multiple:

"10 Clams == 5 USD, 3 EUR, 20 BIT" (Transfer multiple: 1)

"20 Clams == 10 USD, 6 EUR, 40 BIT" (Transfer multiple: 2)

"30 Clams == 15 USD, 9 EUR, 60 BIT" (Transfer multiple: 3)

"40 Clams == 20 USD, 12 EUR, 80 BIT" (Transfer multiple: 4)

"50 Clams == 25 USD, 15 EUR, 100 BIT" (Transfer multiple: 5)

Next, call OT_API_AddBasketExchangeItem() for each currency type in the basket. You will need to to pass the asset account ID for an existing asset account, for each currency type (since you are converting in or out, from your basket account, to your asset accounts.)

Therefore you will call this function once for USD, once for EUR, and once for BIT, in that example, passing in your USD asset acct ID, your EUR asset acct ID, and your Bitcoin asset account ID.

Now that it's all set up, call OT_API_exchangeBasket() to actually message the server and perform the exchange.

Interesting: basket currencies themselves require no more additional system resources than normal currencies! The magic happens during the exchange process. The server simply stores internal asset accounts for the dollars, euros, and bitcoins (say), and it manages the issuer account for the basket, and it also manages the exchanging in and out, by moving digital assets in or out of the internal backing accounts. After that point, a basket is just another Asset Type ID, and requires no additional resources. You can even have baskets made up of other baskets, nested 10 times, and it won't affect the speed of operation of the server!


PROCESSING YOUR INBOX

Process the Receipts and Pending Transfers in your Inbox

If you wish, call OT_API_getInbox() to grab the latest inbox from the server.

In the high-level API, this is often just automated for you, but nevertheless, check out the dl_acct_files.ot script. See also show_inbox.ot, etc.

During this time, your user has the opportunity to peruse the inbox, and to decide which transactions therein he wishes to accept or reject. Usually the inbox is display on the screen, then the user selects various items to accept or reject, and then the user clicks "Process Inbox" and then you do this:

Then call OT_API_Ledger_CreateResponse() in order to create a 'response' ledger for that inbox, which will be sent to the server to signal your responses to the various inbox transactions.

Then call OT_API_Ledger_GetCount() (pass it the inbox) to find out how many transactions are inside of it. Use that count to LOOP through them...

Use OT_API_Ledger_GetTransactionByIndex() to grab each transaction as you iterate through the inbox. (There are various introspection functions you can use in the API here if you wish to display the inbox items on the screen for the user...)

Next call OT_API_Transaction_CreateResponse() for each transaction in the inbox, to create a response to it, accepting or rejecting it. This function creates the response and adds it to the response ledger.

Next, call OT_API_Ledger_FinalizeResponse() which will create a _Balance Agreement_ for the ledger.

Finally, call OT_API_processInbox() to send your message to the server and process the various items.

(See the accept_inbox.ot script.)

If the message was successful, then use OT_API_Message_GetBalanceAgreementSuccess() and OT_API_Message_GetTransactionSuccess() to see just _how_ successful.


MARKETS and PAYMENT PLANS

Setup a Payment Plan

The Merchant draws up the Payment Plan using OT_API_ProposePaymentPlan

Then he sends it to the Customer, who calls OT_API_ConfirmPaymentPlan

The Customer's wallet activates the payment plan by sending it to the server using this function: OT_API_depositPaymentPlan()

(Receipts will process into the respective parties' inboxes.)

Use OT_API_cancelCronItem() to cancel any payment plan (or market offer.)

If the message was successful, then use OT_API_Message_GetBalanceAgreementSuccess() and OT_API_Message_GetTransactionSuccess() as described above in the _deposit cash_ instructions.

Issue a Market Offer

Call this function: OT_API_issueMarketOffer()

(That's the low-level one. See create_offer.ot script for the high-level version.)

Call OT_API_Message_GetSuccess to find out if the message was a SUCCESS or FAILURE.

If the message was successful, then use OT_API_Message_GetBalanceAgreementSuccess() and OT_API_Message_GetTransactionSuccess() as described above in the _deposit cash_ instructions. See the OTScript and Java versions of these calls.

Once an offer goes onto the market, multiple trades may occur between it and the other offers on the market.

(According to the rules in the offers.) Receipts will process into the respective parties' inboxes after each trade.

Cancel a Market Offer

Use OT_API_cancelNymMarketOffer to remove an offer from a market.

If the message was successful, then use OT_API_Message_GetBalanceAgreementSuccess() and OT_API_Message_GetTransactionSuccess()

Retrieving Market Data from OT Server:

OT_API_getMarketList retrieves a list of all the markets available on a specific server, and details for each market. If the server call is a success, the data will be retrieved from the OT server, and written to local storage using the OT Storage API, at this path or key (inside your data_folder location): markets/SERVER_ID/market_data.bin

If you want to verify whether the data is now available in local storage (after a successful call to getMarketList), your code would look like this:

if (otapi.Exists("markets", serverID, "market_data.bin")) bFoundFile = true;

Here is some Java code that reads the market list object from local storage, assuming bFoundFile is true:

	MarketList marketList = null;
	Storable storable = null;

	if (otapi.Exists("markets", serverID, "market_data.bin")) 
	{
		storable =
			otapi.QueryObject(StoredObjectType.STORED_OBJ_MARKET_LIST,
				"markets", serverID, "market_data.bin");
		if (storable==null)
			return null;
            marketList = MarketList.ot_dynamic_cast(storable);
        }

Once you have the market list, here is some sample Java code to read the details of an individual market from that list:

public static Object getMarketDetails(String marketID)
{
	MarketList marketList = Utility.getMarketList();

	if (marketList == null) 
	{
		return null;
	}

	for (int i=0; i < marketList.GetMarketDataCount(); i++)
	{
		MarketData marketData = marketList.GetMarketData(i);

		if (marketData == null)
			continue;

		String [] row = new String[2];

		if (marketID.equals(marketData.getMarket_id())) 
		{
			String[] data = new String[2];
			marketData.getLast_sale_price();
			marketData.getCurrent_ask();
			
			// Etc!! This is where you get the market details.
		}
	}

	// return custom object here (row/data or whatever), or null if failure..
	return null;
}

OT_API_getMarketOffers retrieves publicly-available info for all offers on a specific market, up until maximum depth, and saves the data here: markets/SERVER_ID/offers/MARKET_ID.bin

(See testwallet/OTAPI.i for ALL DATA OBJECTS that are used in local storage, including market offers, recent trades, etc. See the code above for a sample on how those data objects are used.)

OT_API_getMarketRecentTrades: Retrieves all recent trades on a market (up until maximum depth), and stores them here: markets/SERVER_ID/recent/MARKET_ID.bin

To retrieve the offers that a specific Nym has out on the market, use: OT_API_getNym_MarketOffers

This _getNym_MarketOffers_ data is _private_ and thus a lot more detailed than what's retrieved via OT_API_Market_GetOffers, which is more meant for public use.

After a successful retrieval, you can load the data from this location: nyms/SERVER_ID/offers/NYM_ID.bin

If you want to see the Nym's private list of his completed trades, the path to load it from is here:

nyms/trades/SERVER_ID/NYM_ID

There is no need to send a server message in this last case--just read the data from local storage directly. (When market trading receipts are accepted and cleared out of your inbox, this is where they will go. So there's no need to download them, since they were already downloaded through your inbox previously.)

As before, the appropriate data object can be found in testwallet/OTAPI.i along with all the others.


I will be very responsive to developer needs and questions regarding the OT API, so I encourage you to play with the software and contact me anytime.

See also:

opentxs command-line tool

The OT C++ class library

The OTX protocol