Only this pageAll pages
Powered by GitBook
1 of 4

drafts/1.1.0

Loading...

Loading...

Loading...

Loading...

API Usage

The Flow Results specification is designed to be useful in both file-based and API-based environments. File-based usage is ideal for archiving and transferring data manually between systems. However, in many production situations, interoperable systems are likely to exchange data via HTTP-based API services. When implementations provide access to Flow Results Packages and Responses via an API, the following standardized endpoints, parameters, and envelope formats shall be used.

API Authentication

Two methods of authentication are supported for clients accessing Flow Results APIs. All methods should use HTTPS for security.

Token-based authentication

Implementations must support token-based authentication, via the "Authorization" HTTP header, using the Token method. An example of a complete authorization header is:

Authorization: Token 0b79bab50daca910b000d4f1a2b675d604257e42

Implementations can determine the format of tokens. The issuance, expiry, and exchange of tokens is left outside the scope of the Flow Results specification.

HTTPS Basic Auth

Providing additional support for HTTPS Basic Auth is optional, but recommended.

API Request and Response format

The Flow Results API adheres to the JSON API specification, version 1.0, an open standard for how a client should request that resources be fetched or modified, and how a server should respond to those requests, via JSON. All API requests and responses defined below reflect the JSON API norms for query parameters and pagination. JSON API also introduces an envelope structure to embed the Flow Results JSON within additional metadata. Adopting JSON API allows API clients to make use of standard JSON API libraries.

API Endpoints

Five standard API endpoints are defined for Flow Results servers operating in the Data Aggregator role. Two "push" endpoints are used to send flow results to a system playing the Data Aggregator role. Three "pull" endpoints are used to access flow results served by a Data Aggregator.

Endpoints are defined relative to a base URL chosen by the implementation, i.e.:

Base URL: https://my.example-flow-results-server/api/v1

"Push" endpoints to submit flow results to a Data Aggregator

Publish a Package:

This endpoint is used to publish a Package descriptor for the first time to a Data Aggregator.

URL: POST [Base URL]/flow-results/packages

Query parameters: None

Request body: The request body shall specify the type of packages. It shall contain, within the attributes parameter, the JSON structure of the Descriptor.

The id of the Descriptor can be omitted (or null) if the client wants the Data Aggregator (server) to assign a new UUID for this package. If an id is provided, the client must ensure that the UUID does not conflict with a Package id that already exists on the Data Aggregator; servers must reject requests with id conflicts. This is consistent with the JSON API specification for client-generated IDs:

A server MAY accept a client-generated ID along with a request to create a resource. An ID MUST be specified with an id key, the value of which MUST be a universally unique identifier. The client SHOULD use a properly generated and formatted UUID as described in RFC 4122 [RFC4122]. A server MUST return 403 Forbidden in response to an unsupported request to create a resource with a client-generated ID.

Request example:

POST [Base URL]/flow-results/packages HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{  
   "data":{  
      "type":"packages",
      "attributes":{  
         "profile":"flow-results-package",
         "name":"standard_test_survey",
         "flow-results-specification":"1.0.0-rc1",
         "created":"2015-11-26 02:59:24+00:00",
         "modified":"2017-12-04 15:54:44+00:00",
         "id":null,
         "title":"Standard Test Survey",
         "resources":[  
            {  
               "path":null,
               "api-data-url":null,
               "mediatype":"application/json",
               "encoding":"utf-8",
               "schema":{  
                  "language":"eng",
                  "fields":[  
                     {  
                        "name":"timestamp",
                        "title":"Timestamp",
                        "type":"datetime"
                     },
                     {  
                        "name":"row_id",
                        "title":"Row ID",
                        "type":"string"
                     },
                     {  
                        "name":"contact_id",
                        "title":"Contact ID",
                        "type":"string"
                     },
                     {  
                        "name":"session_id",
                        "title":"Session ID",
                        "type":"string"
                     },
                     {  
                        "name":"question_id",
                        "title":"Question ID",
                        "type":"string"
                     },
                     {  
                        "name":"response_id",
                        "title":"Response ID",
                        "type":"any"
                     },
                     {  
                        "name":"response_metadata",
                        "title":"Response Metadata",
                        "type":"object"
                     }
                  ],
                  "questions":{  
                     "1448506769745_42":{  
                        "type":"select_one",
                        "label":"Are you a woman or a man?",
                        "type_options":{  
                           "choices":[  
                              "Woman",
                              "Man",
                              "Other"
                           ]
                        }
                     },
                     "1448506773018_89":{  
                        "type":"numeric",
                        "label":"How old are you? Please enter your age in years.",
                        "type_options":{  
                           "range":[  
                              -99,
                              99
                           ]
                        }
                     },
                     "1448506774930_30":{  
                        "type":"open",
                        "label":"What was the best thing that happened to you today?",
                        "type_options":{  

                        }
                     }
                  }
               }
            }
         ]
      }
   }
}

Response:

The response from the server must adhere to the JSON API specification for POST responses.

Response example:

HTTP/1.1 201 Created
Location: https://go.votomobile.org/flow-results/packages/0c364ee1-0305-42ad-9fc9-2ec5a80c55fa
Content-Type: application/vnd.api+json

{  
   "data":{  
      "type":"packages",
      "id":"0c364ee1-0305-42ad-9fc9-2ec5a80c55fa",
      "attributes":{  
         "profile":"flow-results-package",
         "name":"standard_test_survey",
         "flow-results-specification":"1.0.0-rc1",
         "created":"2015-11-26 02:59:24+00:00",
         "modified":"2017-12-04 15:54:44+00:00",
         "id":"0c364ee1-0305-42ad-9fc9-2ec5a80c55fa",
         "title":"Standard Test Survey",
         "resources":[  
            {  
               "path":null,
               "api-data-url":"https://go.votomobile.org/flow-results/packages/0c364ee1-0305-42ad-9fc9-2ec5a80c55fa/responses",
               "mediatype":"application/json",
               "encoding":"utf-8",
               "schema":{  
                  "language":"eng",
                  "fields":[  
                     {  
                        "name":"timestamp",
                        "title":"Timestamp",
                        "type":"datetime"
                     },
                     {  
                        "name":"row_id",
                        "title":"Row ID",
                        "type":"string"
                     },
                     {  
                        "name":"contact_id",
                        "title":"Contact ID",
                        "type":"string"
                     },
                     {  
                        "name":"session_id",
                        "title":"Session ID",
                        "type":"string"
                     },
                     {  
                        "name":"question_id",
                        "title":"Question ID",
                        "type":"string"
                     },
                     {  
                        "name":"response_id",
                        "title":"Response ID",
                        "type":"any"
                     },
                     {  
                        "name":"response_metadata",
                        "title":"Response Metadata",
                        "type":"object"
                     }
                  ],
                  "questions":{  
                     "1448506769745_42":{  
                        "type":"select_one",
                        "label":"Are you a woman or a man?",
                        "type_options":{  
                           "choices":[  
                              "Woman",
                              "Man",
                              "Other"
                           ]
                        }
                     },
                     "1448506773018_89":{  
                        "type":"numeric",
                        "label":"How old are you? Please enter your age in years.",
                        "type_options":{  
                           "range":[  
                              -99,
                              99
                           ]
                        }
                     },
                     "1448506774930_30":{  
                        "type":"open",
                        "label":"What was the best thing that happened to you today?",
                        "type_options":{  

                        }
                     }
                  }
               }
            }
         ]
      },
      "links":{  
         "self":"https://go.votomobile.org/flow-results/packages/0c364ee1-0305-42ad-9fc9-2ec5a80c55fa"
      }
   }
}

Publish Responses to a Package:

This endpoint is used to publish a collection of Responses for a Package to a Data Aggregator. The POST request can be used multiple times to publish additional responses in batches. Clients should use batching whenever appropriate instead of posting responses individually.

URL: POST [Base URL]/flow-results/packages/[id]/responses

Query parameters: None

Request body: The request body shall specify the type of responses. It shall contain, within the attributes parameter, a single responses attribute, containing the standard Flow Results row array.

Request example:

POST [Base URL]/flow-results/packages/0c364ee1-0305-42ad-9fc9-2ec5a80c55fa/responses HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{  
   "data":{  
      "type":"responses",
      "id":"0c364ee1-0305-42ad-9fc9-2ec5a80c55fa",
      "attributes":{  
         "responses":[  
            [  
               "2015-11-26 04:33:26",
               "11393115",
               "10825354",
               "47029339",
               "1448506769745_42",
               "Man",
               {}
            ],
            [  
               "2015-11-26 04:33:31",
               "11393119",
               "10825354",
               "47029339",
               "1448506773018_89",
               "30.0000",
               {}
            ],
            [  
               "2015-11-26 04:33:35",
               "11393126",
               "10825354",
               "47029339",
               "1448506774930_30",
               "https://go.votomobile.org/audiofiles/download//original",
               {  
                  "type":"audio",
                  "format":"audio/wav"
               }
            ],
            [  
               "2015-11-26 04:34:07",
               "11393169",
               "10825354",
               "47029339",
               "1448506769745_42",
               "Woman",
               {}
            ],
            [  
               "2015-11-26 04:34:13",
               "11393172",
               "10825354",
               "47029339",
               "1448506773018_89",
               "40.0000",
               {}
            ]
         ]
      }
   }
}

Response body: The response from the server must adhere to the JSON API specification for POST responses. Additionally, servers should make use of the 204 No Content response mechanism to report acceptance to clients without sending back long documents.

Response example:

HTTP/1.1 204 No Content
Content-Type: application/vnd.api+json

"Get" endpoints to retrive flow results from a Data Aggregator

List all Flow Results Packages

This endpoint is used to request a list of the Flow Results Packages available on the server for the authorized user.

URL: GET [Base URL]/flow-results/packages

Query parameters: None

Request body: None

Request example:

GET [Base URL]/flow-results/packages HTTP/1.1
Accept: application/vnd.api+json

Response body: The response from the server must adhere to the JSON API specification for fetching a collection of resources. The data array includes the list of package resources. Implementations may decide what summary information they want to publish in the attributes for each package.

Response example:

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
    "links": {
        "self": "https://go.votomobile.org/flow-results/packages?page%5Bsize%5D=100",
        "next": null,
        "previous": null
    },
    "data": [
        {
            "type": "packages",
            "id": "0c364ee1-0305-42ad-9fc9-2ec5a80c55fa",
            "attributes": {
                "title": "Standard Test Survey",
                "name": "standard_test_survey",
                "created": "2015-11-26 02:59:24+00:00",
                "modified": "2017-12-04 15:54:44+00:00"
            }
        },
        {
            "type": "packages",
            "id": "d8d0275f-e108-4528-a259-d738bb626143",
            "attributes": {
                "title": "World Malaria Day Outbound Message",
                "name": "world_malaria_day_outbound_message",
                "created": "2015-05-19 15:59:25+00:00",
                "modified": "2015-06-01 18:57:21+00:00"
            }
        },
        {
            "type": "packages",
            "id": "d24ba50d-e3bf-4eea-b319-ddf8979979d1",
            "attributes": {
                "title": "Example Quotas Survey",
                "name": "example_quotas_survey",
                "created": "2015-12-04 05:45:51+00:00",
                "modified": "2017-11-24 19:58:43+00:00"
            }
        },
        {
            "type": "packages",
            "id": "ba4b5e9e-bb1f-4e92-bfd4-95868ca48b87",
            "attributes": {
                "title": "International Women's Day",
                "name": "international_womens_day",
                "created": "2017-03-08 13:57:15+00:00",
                "modified": "2017-03-09 02:11:31+00:00"
            }
        }
    ]
}

Get the Descriptor of a Package

This endpoint is used to request the Descriptor of a Flow Results Package

URL: GET [Base URL]/flow-results/packages/[id]

Query parameters: None

Request body: None

Request example:

GET [Base URL]/flow-results/packages/0c364ee1-0305-42ad-9fc9-2ec5a80c55fa HTTP/1.1
Accept: application/vnd.api+json

Response body: The response from the server must adhere to the JSON API specification for fetching a resource.

Response example:

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{  
   "links":{  
      "self":"https://go.votomobile.org/flow-results/packages/0c364ee1-0305-42ad-9fc9-2ec5a80c55fa"
   },
   "data":{  
      "type":"packages",
      "id":"0c364ee1-0305-42ad-9fc9-2ec5a80c55fa",
      "attributes":{  
         "profile":"flow-results-package",
         "name":"standard_test_survey",
         "flow-results-specification":"1.0.0-rc1",
         "created":"2015-11-26 02:59:24+00:00",
         "modified":"2017-12-04 15:54:44+00:00",
         "id":"0c364ee1-0305-42ad-9fc9-2ec5a80c55fa",
         "title":"Standard Test Survey",
         "resources":[  
            {  
               "path":null,
               "api-data-url":"https://go.votomobile.org/flow-results/packages/0c364ee1-0305-42ad-9fc9-2ec5a80c55fa/responses",
               "mediatype":"application/json",
               "encoding":"utf-8",
               "schema":{  
                  "language":"eng",
                  "fields":[  
                     {  
                        "name":"timestamp",
                        "title":"Timestamp",
                        "type":"datetime"
                     },
                     {  
                        "name":"row_id",
                        "title":"Row ID",
                        "type":"string"
                     },
                     {  
                        "name":"contact_id",
                        "title":"Contact ID",
                        "type":"string"
                     },
                     {  
                        "name":"session_id",
                        "title":"Session ID",
                        "type":"string"
                     },
                     {  
                        "name":"question_id",
                        "title":"Question ID",
                        "type":"string"
                     },
                     {  
                        "name":"response_id",
                        "title":"Response ID",
                        "type":"any"
                     },
                     {  
                        "name":"response_metadata",
                        "title":"Response Metadata",
                        "type":"object"
                     }
                  ],
                  "questions":{  
                     "1448506769745_42":{  
                        "type":"select_one",
                        "label":"Are you a woman or a man?",
                        "type_options":{  
                           "choices":[  
                              "Woman",
                              "Man",
                              "Other"
                           ]
                        }
                     },
                     "1448506773018_89":{  
                        "type":"numeric",
                        "label":"How old are you? Please enter your age in years.",
                        "type_options":{  
                           "range":[  
                              -99,
                              99
                           ]
                        }
                     },
                     "1448506774930_30":{  
                        "type":"open",
                        "label":"What was the best thing that happened to you today?",
                        "type_options":{  

                        }
                     }
                  }
               }
            }
         ]
      }
   },
   "relationships":{  
      "responses":{  
         "links":{  
            "related":"https://go.votomobile.org/flow-results/packages/0c364ee1-0305-42ad-9fc9-2ec5a80c55fa/responses"
         }
      }
   }
}

Get Responses for a Package

This endpoint is used to request some or all Responses on a Flow Results Package. It supports pagination for large data sets, and a minimum set of filter parameters. Implementations may add support for additional filters.

URL: GET [Base URL]/flow-results/packages/[id]/responses

Query parameters:

  • filter[max-version]: Only included Responses recorded on versions of this Package less recent than and including this version. (This is a timestamp corresponding to the modified field of a Descriptor.)

  • filter[min-version]: Only include Responses recorded on versions of this Package more recent than and including this version. (This is a timestamp corresponding to the modified field of a Descriptor.)

  • filter[start-timestamp]: Only show Responses that were recorded after this timestamp (exclusive). (This is a timestamp in the format of RFC 3339, section 5.6, date-time.)

  • filter[end-timestamp]: Only show Responses that were recorded before and on this timestamp (inclusive). (This is a timestamp in the format of RFC 3339, section 5.6, date-time.)

  • page[size]: The requested number of responses per pagination page

  • page[afterCursor]: The response row_id to requests responses after this id, when paginating forward

  • page[beforeCursor]: The response row_id to request responses prior to this id, when paginating in reverse

Request body: None

Request example:

GET [Base URL]/flow-results/packages/0c364ee1-0305-42ad-9fc9-2ec5a80c55fa/responses?page[size]=5 HTTP/1.1
Accept: application/vnd.api+json

Response body: The response from the server must adhere to the JSON API specification for fetching a resource. The type of the resource must be responses. The attributes field contains a single attribute responses, containing the results row array in Flow Results format.

Response example:

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
    "data": {
        "type": "responses",
        "id": "0c364ee1-0305-42ad-9fc9-2ec5a80c55fa",
        "attributes": {
            "responses": [
                [
                    "2015-11-26 04:33:26",
                    "11393115",
                    "10825354",
                    "47029339",
                    "1448506769745_42",
                    "Man",
                    {}
                ],
                [
                    "2015-11-26 04:33:31",
                    "11393119",
                    "10825354",
                    "47029339",
                    "1448506773018_89",
                    "30.0000",
                    {}
                ],
                [
                    "2015-11-26 04:33:35",
                    "11393126",
                    "10825354",
                    "47029339",
                    "1448506774930_30",
                    "https://example-test-server.com/audiofiles/download/1448506774930_30/original",
                    {
                        "type": "audio",
                        "format": "audio/wav"
                    }
                ],
                [
                    "2015-11-26 04:34:07",
                    "11393169",
                    "10825354",
                    "47029339",
                    "1448506769745_42",
                    "Woman",
                    {}
                ],
                [
                    "2015-11-26 04:34:13",
                    "11393172",
                    "10825354",
                    "47029339",
                    "1448506773018_89",
                    "40.0000",
                    {}
                ]
            ]
        },
        "relationships": {
            "descriptor": {
                "links": {
                    "self": "https://go.votomobile.org/flow-results/packages/0c364ee1-0305-42ad-9fc9-2ec5a80c55fa"
                }
            },
            "links": {
                "self": "https://go.votomobile.org/flow-results/packages/0c364ee1-0305-42ad-9fc9-2ec5a80c55fa/responses?page%5Bsize%5D=5",
                "next": "https://go.votomobile.org/flow-results/packages/0c364ee1-0305-42ad-9fc9-2ec5a80c55fa/responses?page%5Bsize%5D=5&page%5BafterCursor%5D=11393172",
                "previous": null
            }
        }
    }
}

Introduction

Flow Results Data Package

A container and data format for describing a collection of interactions or "responses" reported by end-users of a digital system using the Flow Data paradigm. It provides for the open publication, exchange, and analysis of Flow-generated interactions across supporting platforms.

Authors

Mark Boots (Viamo) Peter Lubell-Doughtie (Ona)

Eduardo Jezierski (InSTEDD)

Gustavo Giráldez (InSTEDD) Evan Wheeler (UNICEF)

Media Type

TODO: once registered: application/vnd.org.flowinterop.results+json

Version

1.1.0

Last updated

2021-07-23

Created

2017-03-31

Table of Contents

  • Language

  • Introduction

    • Scope

  • Terminology

  • Example

  • Specification

    • Components

    • Descriptor

    • Resource

    • Resource Data (found at external path)

    • Question Types

      • message

      • select_one

      • select_many

      • numeric

      • open

      • text

      • image

      • video

      • audio

      • geo_point

      • datetime

      • date

      • time

  • API Usage

  • Changelog

Language

The key words MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL in this document are to be interpreted as described in RFC 2119.

Introduction

Within the field of ICT tools for humanitarian and development work (ICT4D), a range of software applications has emerged for digital data collection and mobile engagement with remote populations. These applications employ a diversity of communication channels, such as text messaging, automated voice calls, unstructured supplementary service data (USSD) menus, web-based forms, and in-person surveys using mobile apps for digital data entry. Despite differences, many of these applications are based on a similar paradigm of "Flow-based" data collection using logical decision trees. However, it was not previously possible to exchange data collected using different applications and vendors unless ad-hoc or one-to-one data mapping software was created.

By defining an open specification for the exchange of data generated by Flow-like software applications, organizations can reduce ad-hoc software development effort; accelerate the creation of new interoperable analysis tools for visualization, dashboards, and decision making; speed response time to sharing data in crisis situations, and reduce risks associated with vendor lock-in.

Scope

The purpose of this specification is to standardize the exchange of data between data collection and data analysis/visualization applications within the ICT4D sector. The focus of the data covered by this specification is the "results" or "responses" recorded during interactions with end-users through digital channels.

The specification is intended to be relevant to both file-based and API-based data exchange. It is agnostic to the communication channel used for data collection.

The specification is self-sufficient and can be used independently, but it is also designed to complement the Flow Definition specification describing logical flows of mobile engagement content. It is also designed to be flexible enough to describe responses collected with non-Flow-based applications, such as the suite of tools based on the Open Data Kit (ODK) framework, and to create a bridge between established and evolving technologies.

Terminology

Contact: A Contact is an end-user of a digital interactive system, providing input or "responses" to the system. Contacts can be human beings interacting via a channel such as interactive voice response (IVR), SMS, USSD, social media messaging, and web browsers. Contacts might also be non-human entities (such as a waterpoint or school) or automated systems (programmable agents) that do not necessarily represent a human being.

Response: A Response is a single input given by a Contact when prompted during an interaction with a digital interactive system. As an example, answering a multiple choice question asking, "Are you male or female?" by choosing the female option constitutes providing a Response.

Question: A Question is a prompt to the Contact for a Response. When looking at results data, knowledge of the nature of the question can help to analyze and visualize it. For example, numeric question responses might be graphed on a scatter plot, while multiple-choice question responses are naturally visualized on a bar chart or pie chart. Often additional information about the question is necessary beyond simply the responses, such as the complete set of choices presented in a multiple choice question.

Although the terminology of "Questions" is natural when using Flows for survey-like use-cases, it's important to clarify that in general, Questions might not be literal questions. They might represent the output of a lookup, script, or logical analysis within a digital engagement system. The terminology used varies across platforms: Variable, Result, and Column are other common terms. Within this specification, we refer to them uniformly for the sake of convenience as Questions.

(TODO: We agreed that Question isn't the best terminology, but I found that while drafting the spec this made it much more legible and understandable, compared to "Variable" or "Result" which are much less precise.)

Example

A minimal example of a Flow Results data package, stored as files on disk, is given here:

There is a Descriptor file in JSON format, e.g. flow-results-example-1.json:

{
  "profile":"flow-results-package",
  "name":"flow-results-example-1",
  "flow_results_specification_version":"1.0.0-rc1",
  "created":"2017-06-30 15:35:27+00:00",
  "modified":"2017-06-30 15:38:05+00:00",
  "id":"b03ec84-77fd-4270-813b-0c698943f7ce",
  "title":"A nice title",
  "resources":[
    {
      "path":"data/flow-results-example-1-data.json",
      "name":"flow-results-example-1-data",
      "access_method":"file",
      "mediatype":"application/json",
      "encoding":"utf-8",
      "schema":{
        "language":"eng",
        "fields":[
          {
            "name":"timestamp",
            "title":"Timestamp",
            "type":"datetime"
          },
          {
            "name":"row_id",
            "title":"Row ID",
            "type":"string"
          },
          {
            "name":"contact_id",
            "title":"Contact ID",
            "type":"string"
          },
          {
            "name":"session_id",
            "title":"Session ID",
            "type":"string"
          },
          {
            "name":"question_id",
            "title":"Question ID",
            "type":"string"
          },
          {
            "name":"response",
            "title":"Response",
            "type":"any"
          },
          {
            "name":"response_metadata",
            "title":"Response Metadata",
            "type":"object"
          }
        ],
        "questions":{
          "ae54d3":{
            "type":"multiple_choice",
            "label":"Are you male or female?",
            "type_options":{
              "choices":[
                "male",
                "female",
                "not identified"
              ]
            }
          },
          "ae54d7":{
            "type":"multiple_choice",
            "label":"Favorite ice cream flavor?",
            "type_options":{
              "choices":[
                "chocolate",
                "vanilla",
                "strawberry"
              ]
            }
          },
          "ae54d8":{
            "type":"numeric",
            "label":"How much do you weigh, in lbs?",
            "type_options":{
              "range":[
                1,
                250
              ]
            }
          },
          "ae54da":{
            "type":"open",
            "label":"How are you feeling today?",
            "type_options":{

            }
          },
          "ae54db":{
            "type":"geo_point",
            "label":"Where are you?",
            "type_options":{

            }
          }
        }
      }
    }
  ]
}

Additionally, there is a data file or API endpoint containing the Responses data described by this resource, in this example, data/flow-results-example-1-data.json. It provides all individual Responses in the following compact JSON format:

[
  [ "2017-05-23T13:35:37.356-04:00", 20394823948, 923842093, 10499221, "ae54d3", "female", {"option_order": ["male","female"]} ],
  [ "2017-05-23T13:35:47.012-04:00", 20394823950, 923842093, 10499221, "ae54d7", "chocolate", {} ],
  [ "2017-05-24T15:15:37.981-04:00", 20394823952, 923842086, 10499224, "ae54d3", "male", {"option_order": ["male","female"]} ],
  [ "2017-05-23T15:16:12.005-04:00", 20394823953, 923842086, 10499224, "ae54d7", "vanilla", {} ],
  [ "2017-05-23T15:16:20.781-04:00", 20394823954, 923842086, 10499224, "ae54d8", 196, {} ],
  [ "2017-05-23T15:16:38.119-04:00", 20394823955, 923842086, 10499224, "ae54da", "I am feeling curious.", {"type": "text", "language": "eng"} ],
  [ "2017-05-23T17:25:12.722-04:00", 20394823956, 923842093, 10499227, "ae54da", "https://myexampleflowserver.org/resources/audio/20394823956.ogg", {"type": "audio", "language": "eng", "format": "audio/ogg"} ],
  [ "2017-05-23T17:25:47.214-04:00", 20394823957, 923842093, 10499227, "ae54db", "[35.678323, -108.25343]", {} ]
]

Changelog

This changelog documents material changes to the Flow Results specification. Versions of the specification adhere to Semantic Versioning.

[Unreleased]

[1.1.0] - 2021-07-30 (proposed)

Added

  • Add optional semantic_labels on Question definitions. This corresponds with semantic_label from the Flow Specification, providing a place for organizations to specify a coding system or taxonomy over Flow Results. (#37)

  • Add optional is_personal_information field on Question definitions. This provides a standard way of indicating fields that contain or might contain personal identifying information in their answers.

  • Add optional set_contact_property field on Question definitions. This provides a standard way for Flow Results to convey to systems that maintain a contact database that the response within a Question should set a contact property. (#41)

  • Add optional set_group_membership field on Question definitions. This provides a standard way for Flow Results to convey to systems that maintain a contact database that the response within a Question should add or remove a contact from a group. (#41)

  • Add message question type to represent interactions with informational messages. (#43)

Changed

  • Clarify that Row IDs should be compared as strings for uniqueness (#38)

[1.0.0-rc.1] - 2017-09-30

  • Complete and stable release candidate

Specification

The Flow Results specification builds on the Data Package specification. Thus a Flow Results Data Package must be a Data Package and conform to the Data Package specification.

Additionally, a Flow Results data package must conform to these additional requirements:

Components

A Flow Results data package consists of one Descriptor, which contains exactly one Resource describing the interaction results.

Descriptor

The Descriptor JSON object must contain the following required metadata properties:

Property

Description

Example

profile

Indicates this package is a Flow Results data package. Must be in the format of the example.

'flow-results-package'

flow_results_specification_version

Indicates the version of this specification the package is compliant with. The Flow Results specification adheres to semantic versioning.

'1.0.0-rc1'

created

The timestamp for when this package was created/published. This must be in the format of RFC 3339, section 5.6, "date-time".

'2017-06-30 15:35:27+00:00'

modified

A version control indicator for the package. Timestamps are used to indicate different versions of a package's schema. This must be in the format of RFC 3339, section 5.6, "date-time". Limited changes are allowed across versions of the same package (i.e.: different versions with the same `id`.). Specifically, new versions of the same package may add additional `questions` within the schema; however, questions may not be removed, and the metadata for existing questions may not be changed. For more information on version support in Flow Results packages, see [Results Versioning](#results-versioning). If this is the original version of the package, `created` and `modified` will be the same.

'2017-06-30 15:38:05+00:00'

id

A property reserved for globally unique identifiers. The Data Packages specification supports any identifiers that are unique including UUIDs and DOIs. Flow Results packages impose the additional requirement that `id`'s are Version 4 UUIDs (RFC 4122). The `id` is a required property, except when a Data Collector uses the Flow Results API to publish a new package to a Data Aggregator. In this case, the `id` may optionally be omitted, and will be assigned by the Data Aggregator and returned. For more information, see the section on .

"b03ec84-77fd-4270-813b-0c698943f7ce"

The following metadata properties are recommended, consistent with the Data Packages specification:

Property

Description

Example

name

A short url-usable (and preferably human-readable) name of the package. This MUST be lower-case and contain only alphanumeric characters along with ".", "_" or "-" characters. It will function as a unique identifier and therefore SHOULD be unique in relation to any registry in which this package will be deposited (and preferably globally unique).

"flow-results-demo-package"

title

A string providing a title or one-sentence description for this package. This provides suggested human-readable text to display as a label for results/visualization of the entire package.

"March 2017 Malaria Protection Survey"

Resource

The Resource describes the interaction results. The Resource must conform to the Data Package Resource specification. Additionally:

Inline data (data in JSON format within the Descriptor) must not be used. This means that either a file path or api_data_url must be provided for the Resource.

The access_method of the Resource is an optional parameter, and can be either api or file:

  • If the access_method is file, it indicates all responses are available in a static JSON file. (The default if this parameter is not provided is file.) When data is available via file semantics, the Resource path shall be a file reference or URL for the complete response data.

  • If the access_method is api, it indicates the resource can be queried using the API Usage specification, with support for pagination and filtering. The Resource api_data_urlmust be provided with the Responses URL on the API server.

The schema property of the resource must be provided inline, and must not use an external schema file or URL.

The schema property must contain a fields object describing the 6 columns within the Resource data. These fields are common to all Flow Results Packages, but are provided here for compatibility with software designed to dynamically read Tabular Data Resources:

{
  "fields":[
    {
      "name":"timestamp",
      "title":"Timestamp",
      "type":"datetime"
    },
    {
      "name":"row_id",
      "title":"Row ID",
      "type":"string"
    },
    {
      "name":"contact_id",
      "title":"Contact ID",
      "type":"string"
    },
    {
      "name":"session_id",
      "title":"Session ID",
      "type":"string"
    },
    {
      "name":"question_id",
      "title":"Question ID",
      "type":"string"
    },
    {
      "name":"response",
      "title":"Response",
      "type":"any"
    },
    {
      "name":"response_metadata",
      "title":"Response Metadata",
      "type":"object"
    }
  ]
}

Question object

The schema property must additionally contain a questions object describing metadata for all the Questions pertaining to Responses in this package. The object identifier (e.g.: 'ae54d3') of questions in this object connects to the Question ID found in each Response row:

{
  "questions":{
    "ae70d7":{
      "type":"message",
      "label":"Welcome Message",
      "type_options":{},
    },
    "ae54d3":{
      "type":"multiple_choice",
      "label":"Are you male or female?",
      "type_options":{
        "choices":[
          "male",
          "female",
          "not identified"
        ]
      },
      "set_contact_property": "gender"
    },
    "ae54d7":{
      "type":"multiple_choice",
      "label":"Favorite ice cream flavor?",
      "type_options":{
        "choices":[
          "chocolate",
          "vanilla",
          "strawberry"
        ]
      }
    },
    "ae54d8":{
      "type":"numeric",
      "label":"How much do you weigh, in lbs?",
      "type_options":{
        "range":[1, 350]
      }
    },
    "ae54da":{
      "type":"open",
      "label":"How are you feeling today?",
      "type_options":{

      }
    }
  }
}

The following properties are required for each question:

Property

Description

Example

type

Describes the semantic type of the Question, which must be from the following list: multiple_choice_one multiple_choice_many numeric open text image video audio geo_point date time datetime

'type':'multiple_choice_one'

label

A human-readable label that can be used to present and provide context for this Question/Response. This is provided in a single default language; localization is left outside the scope of this specification.

'label':'Are you male or female?'

type_options

Dependent on the `type`, an object representing additional metadata for this Question. Required and optional type_options are listed below under Question Types.

'choices':['male', 'female']

The following properties are optional for each question:

Property

Description

Example

semantic_labels (optional, array of strings)

A user-controlled field that can be used to code the meaning of the data collected by this question in a standard taxonomy or coding system, e.g.: a FHIR ValueSet, an industry-specific coding system like SNOMED CT, or an organization's internal taxonomy service. (e.g. "SNOMEDCT::Gender finding"). Zero, one, or more semantic_labels can be specified per question.

"semantic_labels": ["SNOMEDCT::365873007"]

is_personal_information (optional, boolean)

This field can be used to indicate when responses contain or might contain personal identifying information (PII). Systems exchanging this data should use appropriate protection specific to the privacy and security risks of the data.

"is_personal_information": true

set_contact_property (optional, string)

If present and set, indicates that a response to this question persists a contact property with the name given in the string. The string represents a property key, which could be a property name, ID, or other definition as relevant between systems. The Question type can be any one of the supported Question types.

"set_contact_property": "gender"

set_group_membership (optional, string)

If present and set, indicates that a response to the question represents the updated membership of the contact in a group. The question type must be a compatible type that can be parsed as a boolean (select_one, numeric, or open). The convention is that truthy response values will add the contact to the specified group, falsy response values will remove the contact from the group, and null values will not alter the group membership.

"set_group_membership": "farmers"

The schema property may optionally contain a language property. If provided, this must be in the form of ISO 639-3, describing the language of the labels in the questions object. Localization of these labels is left outside the scope of the Flow Results specification.

Resource Data (found at external path)

The Resource path file (or the api_data_url endpoint) must provide the Response data in JSON "row array" format, as shown in the following example:

[
  [ "2017-05-23T13:34:48.325-04:00", 20394823948, 923842093, 10499221, "ae70d7", "1", {"delivery_status": "CONSUMED"} ],
  [ "2017-05-23T13:35:37.119-04:00", 20394823948, 923842093, 10499221, "ae54d3", "female", {"option_order": ["male","female"]} ],
  [ "2017-05-23T13:35:47.822-04:00", 20394823950, 923842093, 10499221, "ae54d7", "chocolate", null ]
]

The Resource must be valid JSON according to RFC 7159. No enhancements or constraints are added beyond the JSON specification.

Each row array shall provide exactly 7 elements ("columns") describing a single Response from a Contact. In order, the columns represent:

#

Column

Description

Examples

1

Timestamp

The date and time the response was given by the contact. The timestamp must be formatted according to RFC 3339, section 5.6, `date-time`, and must indicate the timezone offset of the timestamp. An example is the following format: `2017-05-23T13:35:37-04:00`. If the timestamp is in UTC, the timezone offset of +00:00 shall be used, instead of the `Z` extension. Consistent with RFC 3339, the seconds field may include a decimal point with up to six trailing digits to indicate sub-second precision (e.g. milliseconds or microseconds), such as `2017-05-23T13:35:37.011208-04:00`. Systems are recommended to preserve as much precision as is available in the original timestamp.

2017-05-23T13:35:37.291-04:00

2

Row ID

A unique value identifying an individual Response within the Flow Results package. The value must be unique across all Responses within the entire package. Row IDs may be an integer or a string. (The purpose of Row IDs is for systems offering paginated access to Responses within a Package. Although the rows may not be ordered by Row ID, software hosting data at paginated URLs must maintain an internal ordering based on Row IDs, such that it is possible to return the next X rows after a given Row ID.) Row IDs are compared for uniqueness as strings.

20394823948 '6085f5f2-80a2-423a-9f66-be3b3d777eea'

3

Contact ID

A unique value identifying the Contact that submitted the Response. Contact IDs must be unique for all separate Contacts within a Flow Results Package, and may provide additional meaning between vendor platforms across Packages. Contact IDs may be an integer or a string.

923842093 '43979e6c-6b59-4ccf-a260-4361ebbc3264'

4

Session ID

A unique value identifying a "session" or meaningful group of interactions during which the Contact submitted the Response. For example, a Session ID could link a group of responses from one phone call, one extended SMS conversation, or one ODK form submission. Session IDs may be an integer or a string.

10499221

5

Question ID

A unique value identifying the Question that this Response is for. This connects Response rows to the Question metadata in the Descriptor.

'ae54d3'

6

Response

The actual value of the Response provided by the Contact. The format of the Response is determined by nature of the Question (see below).

'female'

7

Response Metadata

For any Question type, there might be additional metadata describing the Response which varies for each row. This metadata might be required or optional, depending on the Question type. For example, for a multiple choice question, an optional metadata property is the `choice_order` that the multiple choice options were presented in.

{'choice_order': ['male', 'female'] }

Results Versioning

A common occurrence for users is to make minor changes to an underlying flow that has already started collecting data, and to desire for data collected under new and old versions to be reported/aggregated together. (Examples of these minor changes include adding a new question to a flow, or removing a question.) The Flow Results specification provides vendor-optional support for limited changes to flow versions. Implementations may choose to support this functionality or not.

Option 1: No version aggregation under a Package id; each change to a flow creates a new package

Implementations may choose this approach if they do not want to implement any aggregation of responses across multiple versions of a flow, and prefer to leave this aggregation as the responsibility of client software. In this approach, any changes to the schema of a flow (e.g.: adding, removing, or changing questions) would create a new Package with a new independent id. The implementation would serve separate results for different package ids. Client software or external services could examine the Descriptor of each Package and determine, with additional user information, how to aggregate the responses together.

Option 2: Limited changes supported under a Package id; changes to a flow create new versions under the same id

Implementations that wish to provide aggregation of responses across multiple versions of a flow may serve results from multiple versions under a single package id, according to the following constraints. Specifically, newer versions of the same package id may add additional questions within the schema; however, questions may not be removed, and the metadata for existing questions may not be changed. This implies that if a newer version of a flow removes a question from a previous version, the old question will continue to be listed in the schema for the new version. (This ensures that the schema of the most recent version contains a complete set of questions describing all responses in the aggregated resource data, including responses collected under older verions.) The modified timestamp is used as a version control indicator for the Package.

In this case, the response data includes responses collected under multiple versions. API access may implement the filter parameters min-version and max-version to allow clients to selectively retrieve responses from specific versions. (If a client has cached a version of the schema from a Package descriptor, it is recommended to supply the Package's modified descriptor as the max-version when querying the API for responses, to ensure it does not receive responses from newer versions without a corresponding question in the cached schema.)

For changes to flows that go beyond the restrictions above, new Packages with independent ids are required; external clients are responsible for more advanced forms of aggregation across versions of flows.

Question Types

The following Question Types describe the nature of possible Responses. This section lists the required and optional parameters within the schema metadata, and within the Response Metadata for each row:

message

Represents the receipt or consumption of an informational message.

Response Format

The Response must be a number: 0, 1, or a fractional value in between.

How much we know about the consumption of a message depends on the channel capabilities, for example:

  • SMS without delivery reports: All we could know is the message was sent

  • SMS with delivery reports: We can know if the message was delivered (but not if it was read)

  • Social Messaging (Facebook Messenger, WhatsApp, etc.): We can often know if the message was "read"

  • IVR: We know if the message was listened to, and additionally how much of the message was listened to.

Therefore, the Response value column is proposed to be a numeric column with a boolean interpretation, applicable across channel capabilities:

  • A value of 0 is not received

  • A value of 1 means received

  • When channels can measure partial receipt, a value between 0 and 1 indicates percentage receipt. (For example, an IVR message that the contact listened to 71% of the duration can be represented as 0.71).

Type Options (type_options)

None

Response Metadata

Object

Required

Details

Example

delivery_status

Recommended

Provides additional details on the delivery status of the message, as relevant to the channel. Values must be one of: SENT (dispatched to delivery service), DELIVERED (received on the device), CONSUMED (read or listened to by the recipient), SEND_FAILED (failure at sending), or DELIVERY_FAILED (failure at delivery)

"delivery_status": "CONSUMED"

sent_at

Optional

Timestamp when the message was sent, for systems that are interested in tracking times between sending, delivering, and being consumed by contacts.

"sent_at": "2021-03-19T08:08:24+00:00"

delivered_at

Optional

Timestamp when the message was delivered, if applicable.

"delivered_at": "2021-03-19T08:08:30+00:00"

consumed_at

Optional

Timestamp when the message was consumed, if applicable.

"consumed_at": "2021-03-19T08:10:37+00:00"

send_failed_at

Optional

Timestamp when the message failed to send, if applicable.

"send_failed_at": "2021-03-19T08:08:25+00:00"

delivery_failed_at

Optional

Timestamp when the message failed to be delivered, if applicable.

"delivery_failed_at": "2021-03-19T08:08:31+00:00"

select_one

Represents a selection of one choice from a set of discrete choices. (This is a classic multiple-choice question.)

Response format

The Response must be a string; it must be one from the set of choices.

Type options (type_options)

Object

Required

Details

Example

choices

Yes

Array of choices presented to the Contact

{'choices': ['male', 'female'] }

Response Metadata

Object

Required

Details

Example

choice_order

Recommended

When choices might be presented in random order across Contacts, should indicate the order the choices were presented in.

{"choice_order": ["female", "male"] }

select_many

Represents a selection of one or more choices from a set of discrete choices. (This is a multiple-choice question where the Contact can choose more than one option.)

Response format

The Response must be an array of strings, one for each choice selected by the Contact. Each string must be one from the set of choices:

["education", "roads"]

Type options (type_options)

Object

Required

Details

Example

`choices`

Yes

Array of choices presented to the Contact

{'choices': ['roads', 'healthcare', 'education', 'jobs'] }

Response Metadata

Object

Required

Details

Example

`choice_order`

Recommended

When choices might be presented in random order across Contacts, should indicate the order the choices were presented in.

{"choice_order": ["healthcare", "education", "jobs", "roads"] }

numeric

Represents a numeric response; a measurement of a single number.

Response format

An integer or floating-point number:

35

Type options (type_options)

Object

Required

Details

Example

`range`

Optional

When the responses are to be visualized on a scale, provides the minimum and maximum relevant values of the range.

{'range':[0,10]}

Response Metadata

Object

Required

Details

Example

open

Represents a Response that might be in one of several formats. This Question type is useful for representing open-ended Responses to Flows that run over multiple channels (IVR, SMS, social media) and allow the Contact to submit an audio message, image, video, or text response.

Response format

Response must be in the format required for the Question type of each row (where type is identified within the response metadata.)

Type options (type_options)

None used at theschema level. (Refer to the type_options within each row.)

Response Metadata

Object

Required

Details

Example

`type`

Yes

Must be one of the other supported question types (e.g., `text`, `audio`, `image`, etc.)

'text' 'image'

`type_options`

Yes

Includes the schema metadata (normally found in the schema) that would be used for that response row.

{} {'format':'png'}

For additional response metadata, refer to the details for each respective question type.

text

Represents any arbitrary text response.

Response format

A string:

"I am learning this specification."

Type options (type_options)

Object

Required

Details

Example

Response Metadata

Object

Required

Details

Example

`language`

Optional

The ISO 639-3 code for the language of the response, if known.

{'language':'eng'}

image

Represents a picture submitted by the Contact.

Response format

A string with the URL where the image can be retrieved. (TODO: Do we want to support inline image data?)

"https://myexampleflowserver.com/resources/image/23429837433.png"

Type options (type_options)

Object

Required

Details

Example

Response Metadata

Object

Required

Details

Example

`format`

Recommended.

The mime type of the image. If not provided, the format may be guessed from the extension or the Content-Type header of the resource.

"image/png"

`dimensions`

Recommended

The pixel dimensions of the image, if known. If provided, this must be an array of integers, `[width, height]`.

"dimensions": [128, 128]

`file_size_mb`

Recommended

The total file size, if known. If provided, this must be a number in megabytes (MB).

"file_size_mb": 38.35

video

Represents a video submitted by the Contact

Response format

A string with the URL where the video can be retrieved.

"https://myexampleflowserver.com/resources/videos/23429837434.mp4"

Type options (type_options)

Object

Required

Details

Example

Response Metadata

Object

Required

Details

Example

`format`

Recommended

The mime type of the video. If not provided, the format may be guessed from the extension or the Content-Type header of the resource.

"video/mp4"

`language`

Optional

The ISO 639-3 code for the language of the response, if known.

{'language':'eng'}

`dimensions`

Recommended

The pixel dimensions of the video, if known. If provided, this must be an array of integers, `[width, height]`.

"dimensions": [480, 360]

`file_size_mb`

Recommended

The total file size, if known. If provided, this must be a number in megabytes (MB).

"file_size_mb": 38.35

`duration_s`

Recommended

The duration of the recording, if known. If provided, this must be a number in seconds (s).

"duration_s": 16.54

audio

Represents an audio recording submitted by the Contact

Response format

A string with the URL where the audio can be retrieved. (TODO: Do we want to support inline audio data?)

"https://myexampleflowserver.com/resources/audio/23429837435.ogg"

Type options (type_options)

Object

Required

Details

Example

Response Metadata

Object

Required

Details

Example

`format`

Recommended.

The mime type of the audio. If not provided, the format may be guessed from the extension or the Content-Type header of the resource.

"audio/wav"

`language`

Optional

The ISO 639-3 code for the language of the response, if known.

{'language':'eng'}

`file_size_mb`

Recommended

The total file size, if known. If provided, this must be a number in megabytes (MB).

"file_size_mb": 38.35

`duration_s`

Recommended

The duration of the recording, if known. If provided, this must be a number in seconds (s).

"duration_s": 16.54

geo_point

Represents a geospatial coordinate on the surface of the earth.

Response format

Response must be either:

  • An array of two floating point numbers with the latitude and longitude: [lat, long]

  • An array of three floating point numbers: latitude, longitude, elevation (in meters): [lat, long, elevation]

  • An array of four floating point numbers: latitude, longitude, elevation, and accuracy (in meters): [lat, long, elevation, accuracy]

[52.0835780,-106.6104880]

Type options (type_options)

Object

Required

Details

Example

Response Metadata

Object

Required

Details

Example

`address`

Optional

TODO: is this useful?

"Plot 41, Kotei Residential Rd, Kotei, Kumasi, Ashanti Region, Ghana"

datetime

Represents a timestamp with both date and time

Response format

A string containing the date and time in the RFC 3339 date-time format with timezone extension:

"2017-06-30T13:45:58+05:30"

Type options (type_options)

Object

Required

Details

Example

Response Metadata

Object

Required

Details

Example

date

Represents a date. We caution that dates are ambiguous without times and timezone offsets. Interpretation of the date is left to the publishing and consuming platforms. For example, this could be the date of the start of a pregnancy, in an implied local timezone.

Response format

A string containing the date in the format:

"2017-06-30"

Type options (type_options)

Object

Required

Details

Example

Response Metadata

Object

Required

Details

Example

time

Represents a time. We caution that times are ambiguous without dates and timezone offsets. Interpretation of the date is left to the publishing and consuming platforms. For example, this could be the time of day a Contact would like to receive messages, in an implied local timezone..

Response format

A string containing the time in the 24h format:

"14:58:35"

Type options (type_options)

Object

Required

Details

Example

Response Metadata

Object

Required

Details

Example

API Usage