Fetching Resources

Web1on1 accepts many options to manipulate list and detail results for top-level resource types. These options can be added to your request via the querystring to filter, limit, sort and transform your resultsets.

Examples:

GET <apibase>/conversations
GET <apibase>/conversations?field=value
GET <apibase>/conversations?populate=contact,messages
GET <apibase>/conversations?sort=field,-field2
GET <apibase>/conversations?offset=10&limit=10

<apibase>: https://api.web1on1.chat/v2

Mandatory Query Parameters

Most resource listings can have zero or more query filters.

For fetching messages at least one of the following parameters should be supplied: id, organization, conversation, type, role or createdAt.

For fetching conversations using a query for a meta variable, at least one of the following parameters is required: id, type, participants.user, status, createdAt, categoryIndex, category, organization, createdAt or updatedAt.

Example:

GET <apibase>/conversations?meta.intent=greeting&type=contact

In this example, when searching for a meta.intent, we limit the results to only conversations with the "contact" conversation type.

Reserved Query Parameters

In general, document field names can be used as query parameters to filter search result. Additionally, a number of specialized parameters can be used to limit, sort and transform the results. These special parameters are:

  • sort - Sorts by the given fields in the given order, comma delimited. A - sign will sort descending.
  • limit - Limits the number of returned results.
  • offset - Skips a number of results. Useful for pagination when combined with limit.
  • select - Comma-delimited list of fields to select.
  • populate - Comma-delimited list of fields to populate.

Sorting

Getting a sorted list is as easy as adding a sort querystring parameter with the property you want to sort on. /users/?sort=name will give you a list sorted on the name property, with an ascending sort order. /users/?sort=-name will return the same list as before with a descending sort order.

GET <apibase>/users?sort=name
GET <apibase>/users?sort=-name

Response documents may be sorted by multiple criteria. Here's how you'd sort the collection by name in ascending order, then by email in descending order.

GET <apibase>/users?sort=name,-age

Pagination

By default, endpoints paginate results at 200 records per page, ordered by the _id field. Pagination is supported via offset and limit query parameters. When implementing pagination you might want to use offset and limit parameters, to skip a given amount of items or limit to a set amount of items.

GET <apibase>/users?offset=10&limit=10

offset

Skip sending the first n matched documents in the response. Useful for paging.

GET <apibase>/users?offset=5

limit

Limit the response document count to n at maximum. The default limit is 200.

GET <apibase>/users?limit=5

Examples

  • GET /users/?limit=5 will give you the first 5 items
  • GET /users/?offset=5 will skip the first 5 and give you the rest
  • GET /users/?offset=5&limit=5 will skip the first 5 and then give you the second 5

Response Headers

Resultsets are accompanied by meta information in the response headers, which can be useful for pagination. The relevant response headers are:

  • X-Total: total number of results;
  • X-Total-Pages: total number of pages;
  • X-Per-Page: the number of results per page, corresponding to the limit parameter;
  • X-Page: the page number in a paginated set of results;
  • X-Range: the offset and the index of the last paged result, separated by a hyphen.

For example, consider a request for /users/?offset=5&limit=5, where the total number of users available is 9. The corresponding response headers in this case would be:

X-Total: 9
X-Total-Pages: 2
X-Page: 2
X-Per-Page: 5
X-Range: 6-9

A list of these response headers are specified in the standard Access-Control-Expose-Headers header, making them accessible to browser-based applications.

Page navigation links are provided by the API to help your application request further pages of results. API responses, for paged results, contain HTTP Link headers providing a URL used to request other results pages.

Link: <https://api.web1on1.chat.v2/users>; rel="first",
      <https://api.web1on1.chat<apibase>/users>; rel="prev"

Four relationship types are possible:

  • first shows the URL of the first page of results. Not present if the response is the first page in a collection.
  • prev shows the URL of the immediate previous page of results. Not present if the response is the first page in a collection.
  • next shows the URL of the immediate next page of results. Not present if the response is the last page in a collection.
  • last shows the URL of the last page of results. Not present if the response is the last page in a collection.

Pagination in the SDK

Pagination is available if the api is used Promise based. If you use callback methods, you will have to arrange Pagination yourself by reading the headers). Promise based is the future anyway.

Pagination can be used in two different ways in the SDK. Getting the resources by itteration or all at once.

Pagination in the SDK by iteration

Iteration is the cleanest way and works like this:

const Sdk = require('../lib/chipchat');

const sdk = new Sdk({
    token: process.env.TOKEN
});
const conversation = '<your test conversation id with at least 20 messages>';

(async () => {
    // activate pagination with all defaults:
    const iterableMessages = sdk.messages.list({ conversation, pagination: { iterate: true, limit: 100 } });
    for await (const message of iterableMessages) {
        console.log('message: ', messages.id, message.text);
    }
})();

Pagination in the SDK by using .then

But you can also get them without itterating like this:

const Sdk = require('../lib/chipchat');

const sdk = new Sdk({
    token: process.env.TOKEN
});

const conversation = '<your test conversation id with at least 20 messages>';

sdk.messages.list({ conversation, pagination: { limit: 100 } }).then(messages => {
    for (const message of iterableMessages) {
        console.log('message: ', messages.id, message.text);
    }
));

Pagination parameters in the SDK

You can use the following settings when using pagination:

name default description
iterate false Will make the pagination return an paginated itterable object
limit 100 How many result are retrieved per slice
backoff 100 How much time the pagination will wait in between page calls (in ms)
countLimit 2000 How many results will be returned in total. Set to Infinity to have no limit. use wisely
requestLimit 10000 Max nr requests. Set to Infinity to have no limit. use wisely

Field Selection

Selecting the entity-properties you need (collections and details)

If you only need a few properties instead of the entire model, you can ask the service to only give just the properties you need. The select query parameter sets which fields should be selected for response documents.

A GET request to /users?select=name,email would result in something like:

[
    {
        "id": "543adb9c7a0f149e3ac29438",
        "name": "user1",
        "email": "user1@test.com"
    },
    {
        "id": "543adb9c7a0f149e3ac2943b",
        "name": "user2",
        "email": "user2@test.com"
    }
]

As can be seen, the id field is always returned irrespective of selected fields.

Excluding properties from the selection

Instead of specifying which properties to select, you can exclude properties from payloads by prepending the select parameter with a minus character.

A GET request to /conversations?type=contact&select=-messages,-participants would result in a conversations listing with messages and participants excluded from the payload.

CAVEAT

It's not possible to mix inclusion and exclusion of properties; for example the following would be invalid: ?select=-participants,messages.

Field Population

Populating referenced sub-entities

When resulting documents contain properties referencing other entities, you can ask the API service to populate them for you. The populate parameter sets which fields should be populated for response documents.

A GET request to /conversations will result in:

[
    {
        "id": "542edff9fffc55dd29d99346",
        "contact": "591506e18a280627f8dcfede"
        ...
    }
]

A GET request to /conversations?populate=contact will expand the contact for all conversations found, resulting in:

[
    {
        "id": "542edff9fffc55dd29d99346",
        "contact": {
          "organization": "591508af8a280627f8dcfef1",
          "conversation": "222fff111333000000000fff",
          "profile": {
            "name": "John Doe",
            "gender": "male"
          },
          ...
        },
        ...
    }
]

Multiple populate parameters may be specified, separated by a comma. Populated fields will be fetched alongside with, but independent of selected fields (using the select parameter). Population can be applied both to resource listings and individual resources.

Populating arrays of resource IDs

Population also works for resources that have an array of resource IDs as a property. As an example, a conversation has a list of message IDs; to populate all message objects, use:

GET <apibase>/conversations?populate=messages
[
    {
        "id": "542edff9fffc55dd29d99346",
        "messages": [
            {
                "type": "chat",
                ... rest of full message
            }
        ]
        ...
    }
]

Populating Nested Properties

To populate nested properties (inside arrays or objects), use the dot-notation to specify the path to populate. For example, to expand all user IDs into user objects in a conversation's list of participants, use:

GET <apibase>/conversations?populate=participants.user
[
    {
        "id": "542edff9fffc55dd29d99346",
        "participants": [
            {
                "user": {
                    "id": "5a4fd7419feede6a19b18713"
                    "name": "John Johnson",
                    ... rest of full user
                },
                ... rest of participant
            }
        ]
        ...
    }
]

When populating referenced resources, you may be only interested in some properties of the underlying resource - if only to keep the payload size managable. The select parameter mentioned earlier only applies to the immediate resource; to select a set of fields for populated resources, append the populated property with a colon (:) and one or more fields separated by a pipe (|) symbol.

For example, say we want to fetch a single conversation with just the conversation status, the name of the owning organization, the name of participants and two message properties (type and text). The request would look like this:

>GET <apibase>/conversations/5a4fd7419feede6a19b18712?select=status& //
     populate=messages:type|text,organization:name,participants.user:givenName|familyName

This would result in a structure similar to:

{
    "id": "5a4fd7419feede6a19b18712",
    "status": "closed",
    "organization": {
        "name": "Acme, Inc",
        "id": "5a53e8e4dcfa875e82ed2ab3"
    },
    "participants": [
        {
            "user": {
                "givenName": "Edgar",
                "familyName": "Poe",
                "name": "Edgar Poe",
                "id": "5a53e98944cf9c622117fd28"
            }
        }
    ],
    "messages": [
        {
            "type": "postback",
            "text": "startcbot",
            "id": "5a4fd7419feede6a19b18714"
        },
        {
            "type": "command",
            "text": "/join",
            "id": "5a4fd7419feede6a19b18713"
        }
    ]
}

CAVEAT

As you can see, resource IDs are always provided, regardless of field selection. In addition to ids, "derived" resource properties (like participants.user.name) are always included; however these derived property values may be inaccurate if based on non-populated fields. In the above example, any participant's additionalName is not part of the generated "name", because additionalName (here: "Allan") was not part of the populated fieldset.


Search Filters

Any query string parameters, other than those mentioned, will be matched against document properties as search filters to narrow down the resultset. You can ask the service for equality, or values greater or less than, give it an array of values it should match to, or even a regular expression match.

Please note that repeating the same field multiple times in the query string is not supported.

GET <apibase>/messages?text=!
GET <apibase>/messages?text=~regex
GET <apibase>/messages?text=value
GET <apibase>/messages?text=>value
GET <apibase>/messages?text=>=value
GET <apibase>/messages?text=<value
GET <apibase>/messages?text=<=value
GET <apibase>/messages?text=>value1,<=value2
GET <apibase>/messages?text=!=value
GET <apibase>/messages?text=[value1,value2]
GET <apibase>/messages?text=![value1,value2]

Filter Operators

While exact matching using just the equals sign is most common results filter, various types of search filters may be specified by prefixing or surrounding query value(s) with special operators:

Filter Operator Example Description
equal (none) /users?gender=male return all male users
not equal != /users?gender=!=male returns all users who are not male
exist (none) /users?gender= return all users with any gender specified
not exist ! /users?gender=! returns all users without a gender
greater than > /users?age=>18 returns all users older than 18 (age should be a number property)
greater than or equal to >= /users?age=>=18 returns all users 18 and older
less than < /users?age=<30 returns all users age 29 and younger
less than or equal to <= /users?age=<=30 returns all users age 30 and younger
between >,< /users?age=>18,<=30 returns all users older than 18, but younger than or equal to 30
in [] /users?gender=[female,male] returns all female and male users
nin ![] /users?age=![18,30] returns all users with age other than 18 or 30
regex ~ /users?name=~oost returns all users with a name containing 'oost'
nested array {} /conversations?participants={role=admin;accepted=true} returns all conversations that are accepted by an admin participant'

Use OR-criteria for alternate/multiple conditions

To perform OR-queries on multiple fields, separate them with a comma. OR-queries do not support the above operator prefixes, but always perform a case-insensitive regular expression match, or an exact match if the field represents a resource ID. For example:

GET <apibase>/organizations?name,displayName=acme

This would return all organizations where either name or displayName contain the string "acme".

Use dot-notation to search in nested objects

To search in nested data structures, use dot-notation in your filters. For example, to find all users with their language preference set to Dutch, find the appropriate value in the user's settings object:

GET <apibase>/users?settings.locale=nl

Nested arrays can be searched for a single condition by using the dot-notation, too. For example, to find all conversations where a specific user is a participant:

GET <apibase>/conversations?participants.user=5da507d56f7cab2c446f4a50

If you specify multiple nested array fields, the search request will return all records that match any of the conditions (OR-query). For example, to find all organizations with categories that match 'car' and/or contain some specific form:

GET <apibase>/organizations?categories.name=~car&categories.forms=590c76bdde1b762f2113e81c

See the curly brackets method below to match an element on multiple conditions.

Use indexes to count nested array members

To limit by nested arrays, combine the index with the exist/non-exists operator. For example, to fetch all conversations with at least two participants, do

GET <apibase>/conversations?participants.1

Likewise, to fetch all conversations with no more than one participant, do

GET <apibase>/conversations?participants.1=!

Use curly brackets to find nested array members matching multiple fields

In some cases, you may want to find records that match a nested array member on multiple criteria. Using the dot-notation with multiple fields (see above) will not necessarily match the same array member - to look those records, wrap your conditions as key-value pairs inside curly brackets.

For example, to get all conversations in a user's inbox, do:

GET <apibase>/conversations?participants={user=5db4e0fbbf878c1e9643138a;inbox=true}

As an alternative, keys and values may be separated by a colon, and key-value pairs by a comma. Whitespaces are ignored. The following query is identical the previous one:

GET <apibase>/conversations?participants={ user: 5db4e0fbbf878c1e9643138a, inbox: true }

Examples

Get all active conversations:

GET <apibase>/conversations?status=active

Get all queued conversations for an organization:

GET <apibase>/conversations?status=queued&organization=5db4e3bf4c14a433f2f8b644

Get all active conversations for any participant of an organization:

GET <apibase>/conversations?status=active&participants.organization=5db4e3bf4c14a433f2f8b644

Get all active participants for an organization's closed conversations (lingering bots):

GET <apibase>/conversations?status=closed&participants={organization=5db4e3bf4c14a433f2f8b644;status=active}

Get all conversations where a user is active (has joined or accepted):

GET <apibase>/conversations?participants={user=5db4e0fbbf878c1e9643138a;active=true}

Get all conversations that a user has joined:

GET <apibase>/conversations?participants={user=5db4e0fbbf878c1e9643138a;active=true;accepted=false}

Get all conversations that a user has accepted:

GET <apibase>/conversations?participants={user=5db4e0fbbf878c1e9643138a;accepted=true}

Get all conversations in a user's inbox:

GET <apibase>/conversations?participants={user=5db4e0fbbf878c1e9643138a;inbox=true}

Get all conversations that a user is following, and has an inbox notification:

GET <apibase>/conversations?participants={user:5db4e0fbbf878c1e9643138a,follow:true,inbox:true}

Get all conversations that are being followed by an organization's users:

GET <apibase>/conversations?participants={organization=5db4e3bf4c14a433f2f8b644;inbox=true}

Get all conversations accepted by bots:

GET <apibase>/conversations?status=active&participants={role=bot;accepted=true}

Get all queued conversations with active joined-only bots:

GET <apibase>/conversations?status=queued&participants={role=bot;active=true,accepted=false}

Get all queued in any participant's subscribed channels:

GET <apibase>/conversations?status=queued&channels=[5ebdd19745e6ba59efa6b094]

Get all online users for any channel:

GET v2/channels?members.online=true

Get all online channels for a user:

GET <apibase>/channels?members={user=5db4e0fbbf878c1e9643138a;online=true}