[Top] [Contents] [Index]

Yootles: A Social IOU System

A pdf version of this document is available: http://yootles.com/api.pdf.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

1. The Yootles System

Yootles is a system for declaring IOUs between people on a social network. It is designed to allow people to jot down who paid for dinner or other transactions that people often want to but forget to keep track of. But it's useful for much more. It can be used for things like tracking rent payments, sharing utility bills, even tracking interest on personal loans. And it supports non-monetary currencies. Yootles in fact refers to the seminal currency in the system: an abstract measure of happiness or utility used in a suite of forthcoming applications including voting and wagering and various incentive mechanisms.

The next incarnation of the Yootles IOU system will support arbitrary IOU routing (see http://yootles.com/trustnets.pdf). The current version supports bilateral accounting of IOUs with some advanced accounting features. It will always be possible to export your transaction history in an open format so you will never be tied to any particular implementation. (You wouldn't use Flickr without assurance that you could always retrieve your photos--Yootles treats your IOUs the same way.) In fact, your IOUs are always stored exactly as you type them so you can always independently verify everything the Yootles system tells you about your accounts and your balances.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

1.1 Yootles Accounts vs. Yootles Users

A user is a person who logs in to the Yootles system. An account is an entity that can issue and receive IOUs. A user may have several accounts, perhaps subaccounts to keep track of different spending categories, or accounts for friends who are not actual users in the system. Accounts may also be created for purposes such as charity fundraising that aren't tied to any particular user. All accounts are specified by an account group and an account name within that group, separated by a colon (e.g., "smithfamily:alice"). New users creating their first accounts need not know about the concept of groups--in that case a default account is created by making the group name the username and the account name the user's initial(s) or first name, e.g., "alice:ac" or "alice:alice". Note that, while group names must be globally unique, account names must only be unique within groups. For example, jets:bob and sharks:bob are entirely distinct accounts. By default, all users have access to all accounts and simply issuing an IOU to or from a nonexistent account creates that account. We describe this open access philosophy and how to limit it, along with other relationships between users and accounts below (see section Access Control).


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

1.2 IOUs

At its most basic an IOU is a simple transfer from one account to another. We call this an atomic IOU. Yootles also supports two generalizations: repeating IOUs and multilateral IOUs. Fundamentally, all IOUs are broken down into atomic IOUs, but Yootles does not store them this way (1) because this would clutter the transaction history and in fact there is additional information implicit in the fact that an IOU came from a repeating or multilateral IOU that would be lost if all IOUs were atomized.

From a user's point of view a settlement is the opposite of an IOU. The Yootles system, however, has no conception of settlements. When someone makes good on (settles) a past IOU it is recorded as simply another IOU in the opposite direction. We leave it to the user interface to add whatever layer is deemed appropriate to make that intuitive. (Note that this invariably trips people up.)


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

1.3 Repeating IOUs

A repeating IOU specifies a time interval that the IOU automatically repeats, e.g., "every 2 weeks". IOUs can repeat indefinitely or end at a specified time. When an end time is specified it is not taken to be the time of the last IOU but rather a time after which no further IOUs will be generated. The last repeated IOU is prorated for the amount of time between the last IOU and the end time, compared to the repeat interval. For example, a Y$60 IOU that repeats semiannually, issued on 2008 January 1 and ending 2009 April 1 will be atomized into:

Note that, consistent with the above interpretation of end date, if the end date coincides with the last IOU date then the last payment will be prorated to zero. The reason for this interpretation of the end date is that it preserves the property that the total amount paid divided by the elapsed time between start and end is always exactly equal to the IOU amount. User interfaces may want to highlight the prorated amount of the last payment to avoid any confusion. The API makes it easy to do that. (2)


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

1.4 Multilateral IOUs

Multilateral IOUs are IOUs that are shared between some set of accounts. Instead of specifying a single issuer account and recipient account, either or both of these may be a set of accounts, specified as mathematical expressions in which the accounts are treated as variables and the corresponding coefficients indicate proportions by which the IOU amount is split between the issuers or recipients. This turns out to be a simple and elegant way to specify group IOUs, as the following examples illustrate:

Multilateral IOU Atomic IOUs
  • 10 from alice to bob+carol
  • 5 from alice to bob
  • 5 from alice to carol
Multilateral IOU Atomic IOUs
  • 30 from alice+2bob to carol
  • 30*1/3 = 10 from alice to carol
  • 30*2/3 = 20 from bob to carol

I.e., Alice nets -10, Bob nets -20, and Carol nets +30.

Multilateral IOU Atomic IOU
  • 20 from alice+bob to carol+deb
  • 10 from alice to carol+deb
  • 10 from bob to carol+deb

which becomes

  • 5 from alice to carol
  • 5 from alice to deb
  • 5 from bob to carol
  • 5 from bob to deb

I.e., Alice nets -10, Bob nets -10, Carol nets +10, and Deb nets +10.

In the following example, Alice and Bob have dinner and Alice orders a $7 dish, Bob a $9 dish, and the bill with tax/tip comes to $20. They each chip in $10.

Multilateral IOU Atomic IOUs
  • 20 from 7alice+9bob to 10alice+10bob
  • 8.75 from alice to alice+bob(3)
  • 11.25 from bob to alice+bob

which becomes

  • 4.375 from alice to alice (this is a no-op)
  • 4.375 from alice to bob
  • 5.625 from bob to alice
  • 5.625 from bob to bob (also a no-op)

The above has a net effect of 1.25 from Bob to Alice. This is the precise amount, allocating tax/tip proportional to meal costs, that Bob owes Alice after she put in more than her share--10 instead of 7/16*20--for the meal).



The last example shows how--once you're used to the powerful and perhaps initially intimidating language for expressing them--you can track complicated multilateral IOUs by specifying very concisely the nature of the events that occasioned them. This will turn out to be valuable for various Yootles decision and prediction mechanisms. Interfaces can sugar-coat this underlying language in various ways for less sophisticated users. In the initial release of the Yootles Facebook application, the full power of multilateral IOUs will not be exposed at all.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

1.5 Currencies

Currencies can be created for anything--hours of babysitting, borrowed books, beers, ounces of gold, points, kudos, and even, of course, units of happiness. All currencies are publicly available to everyone. There is no such thing as a private currency, just obscure ones. The Yootles system does not track exchange rates between any currencies. It tracks your balances for each currency you have dealt with and keeps them entirely separate.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

1.6 Interest

Every pair of accounts at every moment in time has an interest rate (which applies to all currencies) that causes positive balances to become more positive and negative balances to become more negative (or vice versa if the interest rate is negative, which is allowed (4)). Anyone who can issue IOUs for both accounts (see the Access Control section below) can change the interest rate for an account pair at any time. Interest rates can also be changed retroactively.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

1.7 Credit

Every directed pair of accounts has a credit limit for each currency, initially zero. For example, Alice can state that she trusts Bob up to 10 yootles, meaning that she is willing to issue her own IOU of 10 yootles in exchange for receiving an IOU from Bob for the same amount, assuming the interest rate differential is not unfavorable. Credit limits are the basis of automatic IOU routing (see http://yootles.com/trustnets.pdf). Credit limits can be specified in the current Yootles system but automatic IOU routing is not done. (5)


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

1.8 Access Control

As explained above, there is a strict conceptual separation between Yootles accounts and users. All of the back-end processing is done strictly in terms of accounts, and users can manipulate those accounts according to an access policy. Specifically, there are six flags that specify a given user's relationship to a given account (we use a running example with alice as a representative user accessing the account jets:bob):

The following constraints should hold among these flags:

Note that ctrl does not imply view. (The default is ctrl and view access but it is possible to have only ctrl access but not view access to an account.) Also note that mine does not imply root since anyone can claim an account as their main account or subaccount. This means you can do most of what you might want with no permission but will still have to ask for permission to change the access of others. Notification is critical to such a liberal access policy. Evil Eve can issue IOUs to herself from random accounts all day long but users who manage those accounts can quickly repudiate them.

Finally, consider the case of the user alice creating the account jets:bob for Bob who is not currently a user. No setup is required on Alice's part--issuing an IOU to or from jets:bob automatically creates that account. But instead of or in addition to specifying an account name, a front-end using the Yootles API may allow Alice to specify Bob's email address. In that case the system will create a new user and a new account for Bob and invite Bob to claim the account. Bob can change his username and account name if he wants (6) but if he only has one account the interface should keep him blissfully ignorant of the concept of multiple accounts at all.) The following flags will be set for Alice and Bob and the new account (which we'll continue to refer to as jets:bob for simplicity):

Future versions of Yootles may support a richer language for blocking classes of users.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

2. Use Cases


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

2.1 Issuing IOUs between Facebook users

The Yootles Facebook application is currently the primary client for the Yootles API. Suppose Alice is a Facebook user who just installed the Yootles application. Alice would like to give Bob an IOU. The system should prompt Alice to choose a Yootles username (with an auto-generated default available based on her full name) and a nickname for herself, defaulting to her initials (possibly even a single initial). Suppose her username is alice and her nickname is alc. The system creates the username alice and creates the account alice:alc as Alice's main account. Note that, although the group alice is created in this process, Alice will never need to know about the concept of groups as long as she remains a casual user.

Next, Alice enters the amount and a short string giving the reason for the IOU and selects her friend Bob as the recipient via the usual "start typing a friend's name" interface. More complicated IOUs can be issued by setting other fields but everything except the amount, the recipient, and the reason have reasonable defaults (see section owe (adding or modifying an IOU) for details). If Bob has a main account already, say bob:b, the system uses it and Alice sees in her transaction history an entry like "123 from alice:alc to bob:b for `lunch' on 2007-12-04" (possibly with the "alice:" group prefix redacted). Otherwise, Alice is prompted to choose a nickname for Bob, say "bob", which the system will use to construct an account for Bob using Alice's group, e.g., alice:bob. In this case there is no reason to show the group prefixes and Alice sees an entry like "123 from alice to bob for `lunch' on 2007-12-04".

Bob will be notified that Alice has given him an IOU (as will Alice), with a link to edit it or delete it,(7) but the system requires no action from Bob. Carol might go through the same process as Alice, leaving Bob with two accounts, alice:bob and carol:bob. Both accounts will be marked as belonging to Bob (via the mine field in the access table) but neither will be marked as his main account unless he chooses one. Or he can create a new account altogether and consolidate the balances and close the accounts alice:bob and alice:carol (see section merge (merging/renaming accounts)).


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

2.2 Issuing an IOU in Facebook to someone not on Facebook

This case is similar to the previous one but instead of selecting Bob via the Facebook-style interface, Alice supplies an email address for Bob. The system checks if there is a Yootles user with that email address and, if so, whether that user has a main account. If so, the email address is all that is required. Otherwise, Alice chooses a nickname for Bob and the process continues as above with a new user created for Bob with whatever contact information, such as email address, that Alice provided. Alice can also use the same process without providing an email address or any contact information for Bob. In this case the account created for Bob amounts to merely a subaccount of Alice's. Bob may or may not end up taking control of it in the future.

The notifications Bob receives will be something like: "Alice has given you an IOU for ___. Click here to take control of your account or click here to stop receiving these notifications." Nothing prevents Alice from issuing and IOU from Bob as well (equivalent to a negative IOU to Bob), in which case the notification will be: "Alice has marked you as owing her ___. Click here to take control of your account (or edit/repudiate this IOU) or click here to stop notifications."


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

2.3 Fund-raising with Yootles

Dan announces to his friends that he is fund-raising for the American Lung Association (ALA) and that if anyone would like to donate yootles just transfer them to the account yooniversal:ala. (8) Yootles have no exchange rate with real money but Dan pledges to his friends that however many yootles end up in the ala account, he will donate that many dollars to the ALA (and then transfer the yootles from yooniversal:ala to himself). In effect, his friends are promising him influence in decisions, potential bragging rights in wagers, and other forms of "yootility" in exchange for his donation to a worthy charity.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

2.4 Shared water bill

Housemates can create a common group and easily do shared accounting within that group (as well as with people outside of it). Multilateral IOUs are useful for this. Suppose the housemates each have accounts: elmstreet:alice, elmstreet:bob, elmstreet:carol. A typical IOU might be entered as "$100 from `alice+bob+3carol' to bob for `water bill that Bob paid for and for which Carol used 3 times as much water as anyone else' in the group elmstreet." The previous sections on multilateral IOUs and repeating IOUs (useful for rent payments!) have more details about group accounting (see section IOUs).

Note that this kind of group accounting does not require buy-in from all the members. We have found that it is typically a minority of people in a group who are motivated to track IOUs but that almost everyone is happy to be included so long as they aren't relied upon to do anything. By default, accounts such as elmstreet:carol are open for anyone to view and issue IOUs to and from. All IOUs are repudiable so access can be tightened as it is deemed necessary.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

2.5 Renaming an account

Account names, like jets:bob, are treated as unique identifiers in Yootles--there are no account numbers. This means the process of renaming an account is convoluted, but the interface can mask this. Here we describe the underlying process.

Suppose Bob has an account old:bob he wants to rename to or merge in with new:bob. If old:bob's balances are all zero and Bob has root access he can revoke everyone else's access to old:bob and then simply abandon it. There is no way to actually delete it--this is because entries with old:bob may still exist in people's transaction histories. If old:bob has one or more nonzero balances, renaming consists of transferring those balances to new:bob. Say Alice owes old:bob 8 yootles. By issuing an IOU from old:bob to Alice for 8 yootles we zero the Alice balance Then we issue an IOU of 8 yootles from Alice to new:bob. Now Alice owes new:bob instead of old:bob. We repeat this until all old:bob's balances are zero, and then (optionally) revoke access to old:bob. (9)

The above process can't be entirely hidden from the end users. At the least, users who have balances with old:bob will see two new IOUs, one zeroing out with old:bob and one creating the balance with new:bob. This serves as a natural way to inform all those concerned about account name changes. But from Bob's perspective, the above process can be automated and the API provides a command (see section merge (merging/renaming accounts)) encapsulating the above steps of zeroing out balances in an old account and transferring them to a new account (note that nothing prevents the new account from already existing and having other balances).


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

3. Data Structures for Yootles

The fundamental data structures for accounts, account groups, IOUs, interest, credit, and currencies are given below. These are followed by data structures for users (people who can log in to the Yootles system), aliases (e.g., Facebook ID or email address) and access control (who can do what with which accounts). This is a subset of the underlying database schema. Data types are given in parentheses. Timestamps are integers specifying the number of seconds since 1970-01-01 00:00:00 GMT, i.e., unixtime. In the database, pointers are realized as integer IDs.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

3.1 Data Structures Related to Accounts and IOUs


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

group

An account group name is prefixed to an account name, creating a namespace for a related set of accounts. The fields for the group data structure are group name and group description:


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

account

An account (not to be confused with a user) represents an entity that can issue and receive IOUs, extend or accept credit, etc.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

currency

Currencies can include yootles, real money, time, even non-commodity items such as books (if you wanted to keep track of books you lent to friends).


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

rawIOU

Raw IOUs, which may encompass multilateral IOUs and repeating IOUs, are stored in a way that corresponds directly to what prompted issuing the IOU (see section owe (adding or modifying an IOU)).


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

atomicIOU

Atomic IOUs are the raw IOUs expanded out into bilateral, non-repeating IOUs. Atomic IOUs are also created to keep track of interest payments. All atomic IOUs can be reconstructed from the raw IOUs and the interest rates.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

intRate

This data structure is used to specify an interest rate for a pair of accounts at a given time. Note that interest rates are undirected, so, e.g., alice/bob and bob/alice cannot have different interest rates.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

credit

This data structure is used to specify credit limits (or "trust") between accounts. Credit limits are directed, i.e., they need not be symmetric for a pair of accounts.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

3.2 Data Structures Related to Users

All accounting is done in terms of the data structures in the previous section. There is a strict conceptual separation between users and accounts. Following are data structures pertaining to users.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

user

This data structure stores usernames and passwords for users.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

aliastype

An alias type is an attribute of a user specifying another identifier (besides username) for that user. For example, "real name" or "email address" are alias types.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

alias

The alias data structure gives an attribute/value pair for a user (where the attribute is given by aliastype) in order to specify an alternate identifier for the user, such as Facebook ID or email address. (18)


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

access

The access data structure encodes the ways in which a given user is allowed to access a given account.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

4. The Yootles API

Yootles API calls are made either by a specific Yootles user who specifies their Yootles username and (hashed, salted) password with each call, or on behalf of a specific Yootles user by a trusted application that provides an application-specific user alias and a (hashed, salted) application key with every call.

In both cases, API calls are REST-style over HTTP. Contrary to true REST, the HTTP status code is always set to 200 (success) with any application-level errors indicated in the API output (see section API Output). (20) Standard URI encoding is used in the URLs. Spaces may be mapped either to "+" or "%20". Alphanumeric characters as well as certain characters such as ":" and "_" need not be escaped. The character "+", of course, must be escaped since otherwise it will be decoded as a space.

In the current beta period the API can be accessed at the following URL instead of yootles.com:

http://is002.yrl.re4.yahoo.com

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

4.1 API Calls by Users

The following is a template for an API command when the caller knows the Yootles username (we call this the invoking user) and password:

http://yootles.com/api?cmd=COMMAND
                      &invoker=USERNAME
                      &timestamp=TIMESTAMP
                      &key=KEY

with additional attr=val pairs making up the arguments for the command. For example, here is an example call to issue a simple IOU from Alice to Bob (see section owe (adding or modifying an IOU)):

http://yootles.com/api?cmd=owe&amt=5&from=alice:ac&to=bob:b&why=lunch
                      &invoker=alice
                      &timestamp=1179548280
                      &key=289fe8ab2b3c2c19

In the next chapter we present API calls in an abstracted form. For example, we write the above as

alice> owe(amt=5, from=alice:ac, to=bob:b, why=lunch)

or more generally, as

USERNAME> COMMAND(attr=val, attr2=val2, ...)

This indicates that COMMAND is being called with the given named parameters and that the call is being invoked by USERNAME.

The additional fields (key and timestamp, as well as app, described in the next subsection) are left implicit in the abstracted form. The timestamp field gives the unixtime when the call was issued and the key field must be calculated as

KEY = md5(USERNAME + PASSWD + TIMESTAMP)

where PASSWD is the user's password (and `+' is string concatenation). By hashing the timestamp, and not allowing old timestamps, the system limits replay attacks.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

4.2 API Calls by Trusted Applications

The above suffices for applications that know usernames and passwords. Any user can, for example, use the API with calls like the above to interact with their own accounts and IOUs programmatically. We also allow access by trusted applications that do not (and cannot) know individual users' Yootles passwords but are nonetheless allowed to perform actions on behalf of users. The Yootles system maintains a mapping from identifiers on various services (including Facebook IDs, Yahoo Messenger and AIM screen names, email addresses, phone numbers for SMS, etc.) so that a trusted application need only provide the username or other identifier for its own service. For example, on Facebook if you have the numerical Facebook ID for a user, make the API call as follows:

http://yootles.com/api?cmd=COMMAND
                      &invoker=facebook:FACEBOOKID
                      &app=APPNAME
                      &timestamp=TIMESTAMP
                      &key=KEY

Anyone can apply for an application name (APPNAME) and key (APPKEY) by emailing api@yootles.com. The key field above is then calculated as

KEY = md5(FACEBOOKID + APPKEY + TIMESTAMP).

Since the application uses Facebook's authentication and is trusted, the Yootles password for the user on whose behalf the call is being made need not be provided. Note that the Facebook application must first create a Yootles user (see section addusr (creating new users)) or associate the Facebook ID with an existing Yootles user (see section alias (creating, updating, and querying user aliases)). It may use any convention it chooses (e.g., FirstnameLastname); the addusr command indicates availability of usernames. Users can later change their usernames (see section usr (updating and querying users)), but a user using the Facebook application exclusively need never even know what their Yootles username is. (21)

Other applications are analogous to the Facebook example. For example, the messenger bot application makes API calls of the form

http://yootles.com/api?cmd=COMMAND
                      &invoker=yahoo:YAHOOID
                      &app=yimbot
                      &timestamp=TIMESTAMP
                      &key=KEY

with KEY = md5(YAHOOID + APPKEY + TIMESTAMP). Besides Facebook and Yahoo Messenger, there are additional invoker types for other interfaces including an email bot ("email") and an SMS bot ("4info").

Finally, we allow the API to be called with the same consistent syntax even for calls by users instead of applications. Namely,

http://yootles.com/api?cmd=COMMAND
                      &invoker=username:USERNAME
                      &app=raw
                      &timestamp=TIMESTAMP
                      &key=KEY

and in fact the slightly simpler syntax given in the previous section is syntactic sugar for the above more general format.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

4.3 API Output

If you specify an additional field, output, you can choose the output format from the set {xml, json, perl, lisp, mma, php} with xml the default. (22) These and other output formats are described in the next subsection.

All API calls return a set of labeled values, including a status code and a human-readable message. Formatted as JSON, API output will look like this:

{ "status"  : CODE,
  "message" : MESSAGE,
  ... additional "attr":"val" pairs ... }

CODE is one of the following:

MESSAGE is some human-readable output for the command (useful for command line interfaces such as the messenger bot, and also providing an explanation in case of error). After that come additional attribute/value pairs specific to the individual command, if any. Arguments for commands and their output are detailed in the next chapter.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

4.3.1 Output Formats

Following is a hypothetical response that captures all the structure of the various Yootles API responses, translated into several formats. All except YAML are currently supported. (23)

JSON

{ "status"  : 200,
  "message" : "hello world",
  "foo"     : [{"a":1, "b":2}, {"a":10, "b":20}],
  "bar"     : {"x":"one", "y":"two", "z":"three"} }

Perl

The following perl expression can be directly assigned to a hashref variable. The perl module Data::Dumper generates data in the following form, given a hashref.

{ "status"  => 200,
  "message" => "hello world",
  "foo"     => [{"a"=>1, "b"=>2}, {"a"=>10, "b"=>20}],
  "bar"     => {"x"=>"one", "y"=>"two", "z"=>"three"} }

XML

Using the perl module XML::Simple with options NoAttr and rootname "ytl", the following XML corresponds one-to-one with the perl expression above. Note that the XML output cannot distinguish between a list containing just one element and the element itself. Also, if a list is empty then the XML output will not include the tag for that list at all.

<ytl>
  <status>200</status>
  <message>hello world</message>
  <foo> <a>1</a> <b>2</b> </foo>
  <foo> <a>10</a> <b>20</b> </foo>
  <bar> <x>one</x> <y>two</y> <z>three</z> </bar>
</ytl>

Mathematica

{ "status"  -> 200,
  "message" -> "hello world",
  "foo"     -> {{"a"->1, "b"->2}, {"a"->10, "b"->20}},
  "bar"     -> {"x"->"one", "y"->"two", "z"->"three"} }

Lisp (S-expression)

( ("status" . 200)
  ("message" . "hello world")
  ("foo" . ((("a" . 1) ("b" . 2)) (("a" . 10) ("b" . 20))))
  ("bar" . (("x" . "one") ("y" . "two") ("z" . "three"))) )

PHP

array('status' => 200,
      'message' => "hello world",
      'foo' => array(array('a'=>1, 'b'=>2), array('a'=>10, 'b'=>20)),
      'bar' => array('x'=>"one", 'y'=>"two", 'z'=>"three") )

YAML

---!ytl
status: 200
message: hello world
foo:
  - a: 1
    b: 2
  - a: 10
    b: 2
bar:
  x: one
  y: two
  z: three

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

4.4 Special Syntax for Specifying Accounts and Aliases

As described above, users and accounts are treated distinctly by the Yootles system. Users can access any number of accounts and an account can be accessed by any number of users. Each user, however, has at most one main account and in some applications it is convenient to refer to accounts by the primary user. Additionally, it is often convenient to refer to users by alias instead of username. The Yootles system supports macro expansion in API calls to facilitate this and avoid the need for multiple lookup calls. Specifically, it allows you to specify users by their aliases (such as Facebook ID or Yahoo ID) as well as refer to a user's main account indirectly by user.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

4.4.1 Specifying users by alias

Similar to how accounts are specified by group:name, users may be specified by, for example, yahoo:alice75 or email:alice@alice.com or facebook:24601. Anywhere a username can be specified, an alias can be substituted.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

4.4.2 Bracket syntax for indirectly specifying accounts

The special syntax [t:a] or [u] expands to the main account of user u or the user referenced by alias t:a. This syntax can be used wherever an account is required. An error is returned if the specified user has no main account.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

4.4.3 Macro for username of invoking user

$INVOKER is special syntax that expands to the actual username of the invoking user. This can be used anywhere. For example, set grp=$INVOKER to specify the invoker's username as the account group or use [$INVOKER] to refer to the main account of the invoking user, per the bracket syntax above. (This is equivalent to [t:a] where t:a is an alias for the invoking user.)


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

5. Yootles Commands


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

5.1 usr (updating and querying users)

The usr command allows changing usernames and passwords and looking up users by their aliases, such as email address or Facebook ID. Other commands allow the creation of new users (see section addusr (creating new users)) and adding or changing aliases for users (see section alias (creating, updating, and querying user aliases)).


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

Synopsis

usr()

returns the invoking user's username.

usr(username=u)

changes the Yootles username of the invoking user to u, returning the previous username.

usr(passwd=p)

changes the password of the invoking user to p, returning the previous password. (Note that passwd cannot be specified by applications, only users.)

usr(username=u, passwd=p)

changes both the username and password, returning the previous values.

usr(alias=t:a)

returns the username that has the given alias, t:a, where t is one of the following alias types: (24) {realname, email, yahoo, aol, msn, phone, 4info, icq, google, facebook}.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

Examples

1: Changing your username

If the application issuing the command knows the user's password, the call is made, for example, as follows:

http://yootles.com/api?cmd=usr&username=madeleine
                      &invoker=valjean
                      &timestamp=1234567890
                      &key=3c7e8cc4b89de301

Otherwise, for a trusted application (e.g., the Yootles Facebook application which can make calls on behalf of users) that has an application key, a call like the following is made:

http://yootles.com/api?cmd=usr&username=madeleine
                      &invoker=facebook:24601
                      &app=facebook
                      &timestamp=123890
                      &key=fa3de669ef90ca6

Either of the above are expressed in abstracted form (see section The Yootles API) as:

valjean> usr(username=madeleine)

The following is an example response to the above:

{ "status"   : 200,
  "message"  : "Your username has been changed from valjean to madeleine.",
  "username" : "valjean" }

2: Changing your password

alice> usr(passwd=abc123)

{ "status"  : 200,
  "message" : "Your password has been changed.",
  "passwd"  : "changeme" }

If both username and password are specified, both previous values will be included in the output.

3: Looking up a user by alias

alice> usr(alias=email:bob77@yahoo.com)

{ "status"   : 200,
  "message"  : "Yootles user bob has email address bob77@yahoo.com.",
  "username" : "bob" }

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

5.2 addusr (creating new users)

Any user can call addusr to create a new user. An application creating a new user will also need to call the alias command (see section alias (creating, updating, and querying user aliases)) to create an alias for the new user and the acct command (see section acct (querying and setting access control)) to associate an account with the new user. The account may be an existing account (such as an account created by a friend) or a new account, which can be created with the owe command (see section owe (adding or modifying an IOU)).


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

Synopsis

addusr(username=u)

creates a new user with username u and system-generated password. If the user u already exists, the command will return with status code 402.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

Example

alice> addusr(username=carol)

{ "status"  : 200,
  "message" : "User carol has been created.  Use the `request' command
               to retrieve the password." }

Or, if the username "carol" is taken, the following response is generated:

{ "status"  : 402,
  "message" : "Error: User carol already exists." }

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

5.3 reg (macro for registering/bootstrapping a new user into the system)

The reg command is a macro implemented in terms of the other Yootles API commands. This is a placeholder for more complete documentation of this command.

# Create a new user, associate the alias, create the main account, and
#   link the main account.
# Eg, alias = facebook:24601, username = firstname_lastname, 
#     account = firstname_lastname:firstname
# force defaults to 0; if force=1 then g:ac can't be specified
reg(username=u, alias=t:al, [force=f], [acct=g:ac])  
  if f==0  (0 is the default for f)
    addusr(username=u) and abort if this fails
  else 
    do addusr(username=u) with variations on u until it succeeds
  let u = the username of the added user
  let g:ac = u:u if acct not specified.
  alias(alias=t:al)  # NB: invoked with invoker=username:u
  owe(amt=0.001, from=g:ac, to=yooniversal:admin, why=new_user_fee, cur=ytl)
  acct(user=u, acct=g:ac, main=1, ntfy=1)

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

5.4 alias (creating, updating, and querying user aliases)

The Yootles system stores for each user additional aliases such as email addresses and instant messenger screen names. The alias command allows a user to query and update their aliases, and to add new ones. Other commands allow looking up a user by alias (see section usr (updating and querying users)) and managing accounts for users (see section acct (querying and setting access control)).

The following parameters can be specified:


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

Synopsis

alias()

returns a hash table mapping alias types to aliases for the invoking user. See example 1 below.

alias(aliastype=t)

returns the alias of type t, along with the descriptive name of the alias type. If no such alias type exists, the empty string is returned.

alias(alias=t:a, [aname=n])

adds or updates alias type t to alias a. It returns the previous values, or the empty string if t did not already exist. If aname is also specified, this gives the descriptive name for the alias type (replacing the old one if it exists). See example 4 below.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

Examples

1: Querying all aliases

alice> alias()

{ "status"  : 200,
  "message" : "Your aliases: email = alice@alice.com, 
                             realname = Alice L. Canonikopolous, 
                             facebook = 24601, yahoo = alice84",
  "aliases" : {"username":"alice", "email":"alice@alice.ccom", 
               "realname":"Alice L. Canonikopolous", "facebook":24601, 
               "yahoo":"alice84"} }

2: Querying a specific alias

alice> alias(aliastype=yahoo)

{ "status"  : 200,
  "message" : "Your Yahoo Messenger alias is alice84.",
  "alias"   : "alice84",
  "aname"   : "Yahoo Messenger ID" }

Note that this is also the way to query the descriptive name (aname) for the specified alias type.

3: Querying a username

This works exactly like in the previous example--"username" is treated like any other alias type. (Users, as opposed to trusted applications, will never need this since a user couldn't have issued the alias command without knowing their username.) Note that this usage of the alias command has the same functionality as calling usr with no arguments (see section usr (updating and querying users)).

alice/24601> alias(aliastype=username)

{ "status"  : 200,
  "message" : "Your Yootles username is alice.",
  "alias"   : "alice",
  "aname"   : "Yootles username" }

4: Adding and modifying an alias

alice> alias(alias=openid:oid.org/alice, aname="Open ID")

{ "status"    : 200,
  "message"   : "New alias added: Open ID (openid) = oid.org/alice",
  "aliastype" : "",
  "alias"     : "",
  "aname"     : "" }

The output fields aliastype, aname, and alias give the previous values, or the empty string if this is a new alias.

alice> alias(alias=facebook:24602)

{ "status"    : 200,
  "message"   : "Facebook ID changed from 24601 to 24602.",
  "aliastype" : "facebook",
  "alias"     : 24601, 
  "aname"     : "Facebook ID" }

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

5.5 request (email a user their username and password)

When an application creates a new user, the Yootles system generates a random password for that user, which the application never sees (since applications have application keys and can issue commands on behalf of users without knowing user passwords). A user using a particular application need never know their Yootles username or password, but if the user would like to use some other application that uses the Yootles API, the user will need to provide their username and password to that other application. The request command causes an email to be sent to the user with their username and password.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

Synopsis

request()

returns success and, as a side effect, generates email. If email could not be sent--for example, because no email alias is set (see section alias (creating, updating, and querying user aliases))--it returns status code 402.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

Example

alice> request()
{ "status"  : 200,
  "message" : "Your Yootles username and password has been 
               sent to alice@alice.com" }

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

Known Bugs

There is only one "bug": this command has not been implemented yet. For the current alpha version, the password is just always set to changeme and if you actually change it and then forget it, you'll have to email help@yootles.com. Note that trusted applications, like the Facebook application, do not need to deal with user passwords.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

5.6 acct (querying and setting access control)

The acct command allows management of the access data structure (see section Data Structures Related to Users). That is, it allows the setting and querying of which users have access to which accounts. Parameters for the acct command correspond directly to the fields in the access data structure, namely: user, acct, main, mine, ntfy, root.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index]

Synopsis

acct([user=u])

returns, for user u (default: the invoking user), the main account, a list of mine accounts (accounts for which u has mine > 0), a list of ntfy accounts (accounts for which u gets notifications), and a list of root accounts (accounts for which u has root access).

acct(user=u, acct=a)

returns, for each access field, user u's access to account a.

acct(acct=a)

returns, for each access field, the list of users (possibly empty) who have the corresponding access to account a. Having mine>0 suffices to be included in the list of users having mine access.

acct([user=u], acct