Roster objects

The roster is a simple table containing all of a user's contacts. The keys of the table are contact JIDs (always normalized according to XMPP's JID normalization rules, see util.jid.prep()).

There is an additional key, the boolean value false, which contains a table of metadata relating to the roster itself, or to contacts not currently in the roster (e.g. pending subscription requests).

Example roster:

    [false] = {
        ["version"] = 5; -- Roster version
        ["pending"] = {
            [""] = true; -- Pending subscription request from this JID
            [""] = true; -- Them too.
    [""] = {
        ["subscription"] = "both"; -- See description below of possible subscription states.
            ["groups"] = { "Work", "Friends" }; -- Yes, a contact may be in multiple groups! Groups are more like 'tags'.
    [""] = {
        ["subscription"] = "both";
        ["groups"] = { "Work" };

In general you should not modify the roster object, consider it read-only. If you need to add, remove or modify a contact, use the rostermanager API.

Subscription states

RFC 6121 defines several possible options for the subscription field, and people often get confused by what they mean. It's important to remember that they are always from the perspective of the roster's owner (here called the 'user').

Subscription Description
both The user and the contact have a two-way mutual subscription to each other. I see you, you see me.
to User has a subscription to the contact's presence, and will therefore receive their presence. The contact does not have a subscription to the user, and cannot see their status.
from The opposite of 'to' - the contact can see the user, but the user cannot see the contact.
none Simple, no presence will be exchanged in either direction.