-
Notifications
You must be signed in to change notification settings - Fork 5
Use Cases
WARNING: THESE DOCS ARE NOW OLD / OUTDATED!!!
(UPDATED VERSION COMING SOON.)
The low-level OTAPI has been updated for an important change in the protocol. The below instructions are now wrong, in places, and new instructions will be posted soon.
FURTHERMORE: There is now a high-level API in Java, which wraps this low-level API, and which is now considered the “proper” way to use OT on the client side.
ALSO: The OTScript high-level API still needs to be re-written to match the re-written Java high-level API. This will probably come in the next release.
See the API page for more detailed instructions on each function.
There you’ll find the parameters, the return types… and the notes.
Also see the Install instructions and the Test Wallet commands.
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.
UPDATE: This is now considered a more “low level” API for OT. It’s still the core,
but there is now an Ultra-High-Level API available in Java and in OTScript. It manages
much of the below complexity on your behalf, and reduces OT down to a few simple lines
of code for nearly any use case. (See the scripts/samples folder for examples of this
in action.)
USE CASES for the OT API, described on this page:
- (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 . . . . <==== UNTRACEABLE 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
USE CASES for the OT API
Initialize the library and Load your Wallet
(The user starts up the wallet software.)
Call OT_API_Init()
Then call OT_API_LoadWallet()
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.)
Register a public key (aka “Nym”) at an OT server
Call OT_API_createUserAccount()
.
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()
SERVER MESSAGES
The Request Number
When you message the server, your request number needs to be in sync. Normally it will stay in sync and everything works perfectly. But if the number goes out of sync, your messages will all fail! Just call OT_API_getRequest()
to put it back into sync again. You will probably do this once when you first connect to the server, and then never need to do it again.
Since the request number must increment for each message, it is impossible for an attacker to intercept and replay an old message, (since the request number on the old message is no longer any good.)
Issue a new digital Asset Type
User uploads a new currency contract to the server: OT_API_issueAssetType()
.
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.)
Retrieve Currency Contract (by ID)
Call OT_API_getContract()
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.)
Create a new Asset Account
Clear the reply buffer: Call OT_API_FlushMessageBuffer
.
Wallet sends message to server: OT_API_createAssetAccount()
Server replies with FAILURE/SUCCESS, and the new account is automatically stored in your wallet (if applicable.)
Use OT_API_PopMessageBuffer()
to peer inside the server reply.
Call OT_API_Message_GetCommand
to find out the command (there are many commands possible in an OT message.) Print the command out onto the screen, so you can see what it looks like. That! is the string you want to compare for in your project’s code, to make sure you are looking at the correct reply.
There may be multiple replies in the buffer, but probably not, since we FLUSHED it before sending the message…
Call OT_API_Message_GetSuccess
to find out if the reply was SUCCESS or FAILURE.
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
the Transaction Number
Make sure your wallet always has a supply of transaction numbers.
Call OT_API_GetNym_TransactionNumCount()
to see how many transaction numbers are currently in your wallet.
Call OT_API_getTransactionNumber()
to get more numbers when you are running low.
(All transactions require a transaction number that was specifically issued to you by an OT Server.)
(Your transaction numbers remain outstanding to you until you close out their actual transactions.)
You don’t have to juggle these transaction numbers—OT does it automatically in your wallet—but you do need to make sure you have some available, and replenish when they’re getting low. I recommend just requesting 10 more of them whenever you have less than 5 available. (OT auto-receives all new #s in reply from the server, and stores them in your wallet.)
Make sure you have the latest intermediary files before doing a transaction:
All transactions, in addition to requiring a transaction number, also require a balance agreement. (The wallet performs this behind the scenes when you request any transaction.)
IMPORTANT: 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. Really, only the account and inbox will change “behind your back” (that is, on the server side), but you still need to grab the outbox at least once: when you first create an account, before the first transaction. Your balance agreements will succeed as long as you have the latest copies of these files. To retrieve them from the server, call these functions:
OT_API_getAccount()
OT_API_getOutbox()
OT_API_getInbox()
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: OT_API_depositCheque()
Server replies success or failure.
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 untraceable cash, which is stored in the purse folder in local storage.
Deposit cash
Alice calls OT_API_FlushMessageBuffer
.
Alice sends message to server requesting deposit: OT_API_notarizeDeposit()
Server replies success or failure.
Call OT_API_PopMessageBuffer()
to get the server reply out of the buffer. Since you just flushed the buffer (above), we already know what kind of message we’re expecting to find (it’s a “@notarizeTransactions” message containing an “atDeposit” transaction.)
Call OT_API_Message_GetCommand
if you want to see the exact command you’re holding, just to make sure you’re looking at the right message (See OTMessage.cpp for all the different commands, if you’re curious to see them all + their data!)
Call OT_API_Message_GetSuccess
(and pass it the server reply) to find out if the message was a SUCCESS or FAILURE.
WARNING: Just because a MESSAGE was successful, does NOT mean that the TRANSACTION INSIDE THAT MESSAGE was also successful! The message may have processed normally, yet the server may have still refused the transaction inside that message for whatever reason (expired, etc.) You might have a perfectly valid message informing you that your cheque deposit failed due to a bounced cheque.
FYI, not all messages contain transactions, but deposit cash DOES.
You will find this useful:
If any Message FAILS, it’s possible that your Request Number got out of sync. Just call OT_API_getRequest() and then try the message again.
FOR TRANSACTIONS:
If the Message SUCCEEDS, next check to see if the BALANCE AGREEMENT was also successful. (All Transactions must include a balance agreement, which the server will verify before signing, and which will form part of your receipt.)
To verify the balance agreement, OT_API_Message_GetBalanceAgreementSuccess()
will prove useful to you. (Even a perfectly valid transaction will be automatically rejected by the server if the balance agreement is wrong. So you need to check the server’s reply and see if your balance agreement was a success.)
If your balance agreement is failing, it could be because a cron item has expired (payment plan, market offer, etc) and the transaction number has come off of your list (you just don’t know it yet.) To fix this, call OT_API_getNymbox()
to download any notices of this nature, wait a few MS, and then try again.
If your balance agreement is a SUCCESS, then verify the transaction itself to see if it succeeded. To verify a transaction, use OT_API_Message_GetTransactionSuccess()
or OT_API_Transaction_GetSuccess()
. When this verifies, it means your withdrawal, or deposit, or whatever, actually went through, and you now have a receipt.
The receipt will be saved automatically into your receipts folder, whether success or fail.
The next time you download your inbox, you’ll want to call OT_API_VerifyAccountReceipt()
, which uses that last receipt to make sure the server isn’t screwing you.
AGAIN: Whenever you download the latest copy of your account balance, or your inbox, or any other such intermediary files, how do you know the server isn’t screwing you over by getting you to sign a new balance agreement based on some WRONG balance? Because, you are ALWAYS able to VERIFY those intermediary files against your LAST SIGNED RECEIPT, by calling OT_API_VerifyAccountReceipt()
. Do you understand how important that is? It should be performed anytime those intermediary files have been downloaded from the server. This receipt is what protects the client from getting SCREWED. (Do you know what it feels like to get screwed?)
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.
You also have the option to dig the data out of the server reply yourself, as shown above, by popping it from the reply buffer. (Those replies are always accumulating in the buffer, until you pop/flush them out.) There are various API calls for introspection on the messages, they usually start with OT_API_Message_
.
BOX RECEIPTS: Any of the ledger boxes (Nymbox, Inbox, Outbox) now only contain abbreviated versions of their contents, instead of the full receipts. (At some point the boxes had gotten too large to download as a single file, so the contents were separated out into individual files.)
Thus, once you download the ledger itself, iterate through it and use OT_API_DoesBoxReceiptExist
for each receipt in it. If it doesn’t then use OT_API_getBoxReceipt
to download it from the server. (Using the normal flush/call/pop pattern to check for success.)
NOTE: The new “Ultra-High-Level API” manages all of this complexity for you! See the scripts/samples folder, as well as the Java code for the Moneychanger test GUI, to see examples of it in action. All of the above gets reduced down to a couple of lines of code!
Account-to-Account Transfer
Call OT_API_notarizeTransfer()
to send a transfer from one asset account to another.
(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.)
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!
Call OT_API_FlushMessageBuffer
Call OT_API_withdrawVoucher()
to send the request to the server.
Then, call OT_API_PopMessageBuffer()
to retrieve any server reply.
If there is a message from the server in reply, then call
OT_API_Message_GetCommand()
to verify that it’s a reply to the message
that you sent, and then call OT_API_Message_GetSuccess()
to verify whether
the message successful.
If the message was successful, then use OT_API_Message_GetBalanceAgreementSuccess()
and OT_API_Message_GetTransactionSuccess()
as described above in the deposit cash instructions.
If it was all a success, next call OT_API_Message_GetLedger()
to retrieve
the actual “reply ledger” from the server.
Penultimately, call OT_API_Ledger_GetTransactionByID()
and then,
finally, call OT_API_Transaction_GetVoucher()
in order to retrieve
the voucher cheque itself from the transaction.
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.
If the message was successful, then use OT_API_Message_GetBalanceAgreementSuccess()
and OT_API_Message_GetTransactionSuccess()
as described above in the deposit cash instructions.
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
Call OT_API_FlushMessageBuffer
Call OT_API_getInbox()
to grab the latest inbox from the server.
Then, call OT_API_PopMessageBuffer()
to retrieve any server reply.
You will also probably want to call OT_API_getAccount
as well as
OT_API_getOutbox
, using the above method, since you need to have
the latest versions of those files, or your balance agreement will
be calculated wrong, causing your transaction to fail.
NOTE: You only have to getOutbox for a brand new account. After that,
OT will keep it in sync automatically. But the Account and the Inbox
need to be downloaded all the time, since they change on server side
occasionally.
Then call OT_API_LoadInbox()
to load the inbox ledger from local storage.
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.
If the message was successful, then use OT_API_Message_GetBalanceAgreementSuccess()
and OT_API_Message_GetTransactionSuccess()
as described above in the deposit cash instructions.
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
Clear the reply buffer: Call OT_API_FlushMessageBuffer
.
Call this function: OT_API_issueMarketOffer()
Server replies with FAILURE/SUCCESS…
Use OT_API_PopMessageBuffer()
to grab a copy of the server reply.
Call OT_API_Message_GetCommand
to verify it’s the correct one. (There may be multiple replies in the buffer, but probably not, since we FLUSHED it before sending the message…)
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.
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. Use Flush / Pop / GetSuccess as above, to see if your call was a success.
If the message was successful, then use OT_API_Message_GetBalanceAgreementSuccess()
and OT_API_Message_GetTransactionSuccess()
as described above in the deposit cash instructions.
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:
The OT API
Installation
Test Wallet commands
Diagrams: Architecture Overview, Fully-Anonymous (cash only), and Pseudo-Anonymous (using accounts).