Suggest Edits

Introduction

 

Welcome to Cortex! In this Cortex reference, you'll find information and examples on transacting with the Cortex API; creating custom objects and properties; working with standard objects such as Accounts, Connections, and Notifications; searching and aggregating your data; and creating custom scripts.

If you haven't already, be sure to Sign Up to create your development org.

In the API sections, you'll find a live API explorer. This API explorer is a good way to get familiar with how Cortex authentication works, how objects are created and shared, and more. You'll notice that the first section (Org) can be queried without an authenticated session. Just click "Try It" and it will work with your org name and API key. This is because your Org has publicly available information. If you don't yet have an API Key, follow the instructions to Generate API Key to get started.

To start creating your own custom Cortex objects, check out the documentation on Data Model Setup.

Have a question? Ask it in our community-driven FAQ. We'd love to hear from you.

Happy Coding!

Suggest Edits

Organizations

 

In Cortex, your org (short for organization) is your private Cortex environment. Only you and those you allow have access to this environment and the data within it.

Org Environments

Production

Medable environment that has active end-users and is storing critical and/or sensitive data.

Production orgs are accessed from the following endpoints

Development

Medable environment used for active development and testing of applications without impacting production environments.

Development orgs are accessed from the following endpoints

Note

Critical or sensitive data should not be stored in development orgs as these orgs do not employ all of the necessary protection safeguards.

Suggest Edits

Making Requests

 

When making Cortex API requests, the following are required

  • API Endpoint
  • API Client Key

API Endpoint

The API endpoint takes the following form:

https://<org_api_endpoint>/<org_name>/v2/<api_resource>

Where:

  • org_environment_endpoint is the proper API endpoint for your org environment
  • org_name is the name you provided when signing up
  • api_resource is the Cortex API resource you are accessing. This could be a Cortex object or a custom route.

For example, if your org name was newhealthco and you were accessing the Organization Object in your Cortex dev environment, your fully formed endpoint would look like:

https://api.dev.medable.com/newhealthco/v2/orgs

Request Headers

All API calls require the Medable-Client-Key header, this is populated with an API Key that is generated when you create your app in Cortex. To create your API key, see Generate API Key. Additionally, if you configure your app with CSRF protection, a Medable-Csrf-Token will also be required. In this case, each authenticated request will return an HTTP response header of the same name, and the subsequent request must contain the value of that response header.

Header
Value

Medable-Client-Key

API key. See Generate API Key

Medable-Csrf-Token

When app configured with CSRF protection, authentication and request to authenticated routes will produce a "medable-csrf-token", which must be sent as a request header with each subsequent call.

Important

You must ensure that withCredentials is set to true. Otherwise the secure cookie will not be set on your browser. If you're using one of our mobile SDK's, all of this is handled for you.

Example GET /accounts/me

$.ajax({
    url: "https://api.dev.medable.com/example/v2/accounts/me",
    type: "GET",
    contentType: "application/json; charset=UTF-8",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq",
        "Medable-Csrf-Token": "MvFkpcS0BCM9qpf4K0pFMyiE57e3VtI5Cb38NfQn6eWiPPp6CqZCOOrAljDZYWnU"
    }
});
var request = new Request('https://api.dev.medable.com/example/v2/accounts/me', {
	method: 'GET',  
	credentials: 'include',
	headers: new Headers({
    'Content-Type': 'application/json; charset=UTF-8',
    'Medable-Client-Key': 'GsAqlhnIMzrDeD8V2MBQWq',
    'Medable-Csrf-Token': 'MvFkpcS0BCM9qpf4K0pFMyiE57e3VtI5Cb38NfQn6eWiPPp6CqZCOOrAljDZYWnU'
	})
});

Request Methods

GET

GET requests let you read one or many instances of a resource. They typically take one of two forms

List (Many)

GET /<object_name>

Read (One)

GET /<object_name>/<object_id>

Or if pathing to a property

GET /<object_name>/<object_id>/<property_path>

POST

POST requests allow you to create a new object instance from the request body. If the request is applied to an array property, the new array elements are pushed onto the existing array.

Create

POST /<object_name>

{
  c_property1: 'value',
  c_property2: true,
  c_property3: [1, 2, 3]
}

Push

POST /<object_name>/<object_id>

{
  c_property3: [4, 5, 6]
}

PUT

PUT requests allow you to update an existing object instance with the contents of the request body for the provided object instance _id. If the request is applied to an array property, the entire array is replaced with the request body.

Update

PUT /<object_name>/<object_id>

{
  c_property1: 'new value'
}

PATCH

PATCH requests let you chain operations together on an object instance in one request. For example, if you have an object instance that you'd like to update the value of one property (ordinarily a PUT request), push a value into an array property (ordinarily a POST request on a path), and delete another property (ordinarily a DELETE request on a path), that would take three requests. However, with a PATCH, you can achieve this in one request containing three operations.

Patch

PACH /<object_name>/<object_id>

[{
    op: 'set',
    value: { c_property1: false }
},{
    op: 'push',
    path: 'c_array',
    value: 5
},{
    op: 'unset',
    value: {
      c_property1: 1
    }
}]

Patch Operations

Operation
Description

set

Update the value of a document or property

{
    op: 'set',
    path: 'c_property1', 
    value: 'new value'
}

OR

{
    op: 'set',
    value: {
        c_property1: 'new value'
    }
}

unset

Delete a property or properties from the instance.

{
    op: 'unset',
    value: {     
        'c_property1': 1,
        'c_property2': 1
    }
}

push

Push a value or array of values into an array property

{
    op: 'push',
    path: 'c_property3', 
    value: [4, 5]
}

OR

{
    op: 'set',
    value: {
        c_property3: [4, 5]
    }
}

remove

Remove a value or array of values from an array. If a value exists multiple times in the array, all values will be removed.

{
    op: 'remove',
    path: 'c_property3', 
    value: [1, 3]
}

OR

{
    op: 'remove',
    value: {
        c_property3: [1, 3]
    }
}

DELETE

DELETE requests allow you to delete the object instance for the provided object _id

DELETE /<object_name>/<object_id>

For additional examples and details on making Cortex API requests, see First API Request

Suggest Edits

Authentication

 

Cortex employs session-based (using cookies) and signature-based authentication. Within each org, applications can be created which provide the necessary key and secret for API access. See Generate API Key for more details.

Session-Based Authentication

A typical use of session-based authentication would be for a client application, such as a mobile or web app, whereby individual users authenticate using their credentials to initiate a new session.

The session is unique to the authenticated user and will timeout after a period of inactivity, based on org settings. Account registration or logging in both initiate authenticated sessions.

When employing session-based authentication, Two Factor Authentication also applies.

Signature-Based Authentication

A signing key allows a third-party to make privileged calls to the API using a secure request signing mechanism. These keys can be configured for single or multiple user accounts, timed expiry, etc. Such a mechanism can be useful for scenarios such as back-end system integrations (e.g. Integrations with an EMR, or HL7 messaging appliance).

Signed Request Headers

Name
Value

Medable-Client-Signature

The calculated request signature.

Medable-Client-Timestamp

Client Unix Timestamp in milliseconds. The server issues a Medable-Server-Time responsed header with each operation which clients can use to synchronize.

Medable-Client-Nonce

A client-generated nonce matching /^[a-z\d]{16}$/i, used to prevent replay attacks.

Medable-Client-Account

Optionally sets the calling principal by account id (if the app is configured to allow principal override).

Example signed request

// Example signature-authenticated request using nodejs

'use strict';

function generateNonce() {
    var chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
        maxC = chars.length-1,
        nonce = '',
        length = 16;
        
    while(length--) {
        nonce += chars[Math.round(Math.random() * maxC)];
    }
    return nonce;    
}

var crypto = require('crypto'),
    request = require('request');
      
var command = '/connections', // use only the path component (no query strings)
    method = 'GET', // uppercase http method
    apiKey = 'GsAqlhnIMzrDeD8V2MBQWq',
    apiSecret = 'Kzc8nwCQiKOgiwTIobaI3H6ryK4C5fC0QcYsuXCSbEMKcJPz8EU2phcj6akDB9VP',
    timestamp = Date.now(),
    hmac = crypto.createHmac('sha256', apiKey+apiSecret),
    signature;

hmac.update(command + ';' + method + ';' + timestamp);
signature = hmac.digest('hex');

var options = {
    url: 'https://api.dev.medable.com/example/v2/connections',
    headers: {
        'Medable-Client-Key': apiKey,
        'Medable-Client-Signature': signature,
        'Medable-Client-Timestamp': String(timestamp),
        'Medable-Client-Nonce': generateNonce()        
    }
};
  
request(options, function(error, response) {
    // ...
});     

Authentication

Token Authentication and Scoping

Beta Feature

For now, generating and revoking auth tokens is limited to the scripting interface. See the Scripting Accounts Module section for more examples and full token options.

Applications can leverage JWT (JSON Web Tokens) to access Cortex. Once a key-pair has been generated, tokens can be generated from either session-based or signature-based apps.

  • To enable token signing, Generate RSA key pairs for each app you wish to authenticate.
  • The default limit of permanent/limited-use authentication tokens per account in the app is 10.
  • Check Expose Keys to add this app's JWK to the list produced in GET /auth/certs. Useful if you want third-parties to validate tokens generated by your app.

To invalidate all tokens for an app you must regenerate the key pair or delete the app altogether. You can invalidate permanent/limited-use tokens per subject using Account.revokeAuthToken() and Account.revokeSubjectTokens(). Ephemeral tokens (those without a jti) can only be revoked by deleting the application or regenerating the key-pair.

The following table outlines the JWT claim set supported in Cortex.

Claim
Description

aud

The audience. This is always script.env.url.

iss

The issuing application's api key.

iat

The unix timestamp when the token was generated.

nbf

When present, the unix timestamp when the token becomes usable.

exp

When present, the unix timestamp when the token expires.

sub

The account identifier of the token's calling principal. The token will authenticate as this account when used with Cortex.

jti

When present, represents the unique token identifier. This will exist for permanent and limited-use tokens.

cortex/scp

The token scope. Scopes limit token access to sections listed in the claim.

See Authentication Scoping.

cortex/rls

An array of roles granted to the token, and merged with the token subject's existing roles.

cortex/skp

When set, the token skips access controls for the purpose of limiting matches. The scripting analogue to this claim is skipAcl.

cortex/skc

When set, the token skips access controls for instance creation. The scripting analogue to this claim is bypassCreateAcl.

cortex/gnt

When set, the token grants this level of access to any and objects accessible to the token. The scripting analogue to this claim is grant.

cortex/cnt

When set, represents the maximum number of times the token can authenticate before invalidating.

Scoping

A powerful new scoping feature has been added that allows you to limit access to a subset of functionality, like object access, deployments, script and view execution, and administration functions.

All access tokens are scoped, and adding scope is done by adding one or more scope chains to the token in the cortex/scp claim, or inheriting them from subject roles and those added with cortex/rle claims.

Valid scope examples:

  • object.read.account.*.name
  • script.execute (same as script, script.execute.*)
  • view.execute.c_daily_report

Invalid scope examples:

  • object.read.account.name (missing identifier or * before property)
  • deployment.create (use object.create.deployment instead)
Scope Chain
Level
*

The token can perform all operations as the calling subject.

object
[*, create, read, update, delete]
[*, object[#type]]
[*, identifier]
[fqpp]

Object operations, such as reading accounts, creating connections, etc.

The last element in the chain (fqpp) can be used to limit access to individual properties (e.g. c_set[]#c_foo.c_string_arr[]). You can see the fqpp (fully-qualified property path) in your schemas (GET /schemas).

Examples:

object.read.c_step_response#c_boolean.*.c_value allows reading c_value from all c_step_response objects of the c_boolean type.

object.*.c_comments.5953f7dc749219f1a2eee1ee allows full access to a specific instance of c_comments (assuming the subject principal already has access).

script
[*, execute]
[*, route, runner]
[identifier]

This scope is required if the token is used to run script routes or use the ad-hoc script_runner system route. For routes, an Identifier can be added to the chain to limit use to a single route.

view
[*, execute]
[code, identifier]

This scope is required if the token is used to run script routes. An Identifier can be added to the chain to limit use to a single view.

deployment
[*, execute]
[identifier]

This scope is required if the token is used to execute deployments via scripted deployment automation.An Identifier can be added to the chain to limit use to a single deployment.

admin
[*, read, update]

This scope is required if the token is used to call administrative routes, such as user provisioning, deactivating accounts, etc.

Scopes in Views

Views execute without scope; only view.execute.[view name] is required to run a view, supporting object.read scopes are not required.

However, any other claims (grant, skipAcl, roles, etc.) are still applied.

Scopes have been added to custom roles. Tokens inherit the scopes from roles held by the principal, as well as any roles granted by the cortex/rls claim. In the image below, the Scoped role add the ability to execute any view and a single scripted route.

const Account = org.objects.account;
      
const account_id = Account
  .find({email: 'james@medable.com'})
  .skipAcl()
  .grant(4)
  .next()
  ._id;

// create an ephemeral token that allows the caller to act as account_id and 
// read the account name and the subject of all c_message instances, skipping
// access control.
return org.objects.account.createAuthToken(
  'yk8XJmrMKWzhinCl4Ww99A',
  account_id,
  {
    scope: [
      `object.read.account.${account_id}.name`,      
      "object.read.c_messages.*.c_subject"
    ],
    skipAcl: true,
    grant: consts.accessLevels.read
  }
)
'use strict';
const request = require('request'),
      token = 'eyJhCiJSUz...c4DiCkVvNA',
      options = {
        url: 'https://api.dev.medable.com/example/v2/c_messages',
        headers: {
          Authorization: `Bearer ${token}`
        }
      };
  
request(options, function(error, response) {
    // ...
}); 
Suggest Edits

Cortex Objects

 

Cortex objects are containers for data and functionality. For data-modeling purposes, you can think of a Cortex object like a database table. However, Cortex objects come with many more inherited capabilities than just data storage. For example, a Cortex object lets you specify fine-grained access controls for the objects and their properties, they allow for sharing data with others using connections, you can sub-class Cortex objects into multiple types, and you can extend objects with custom logic via triggers.

Cortex provides a number of standard objects to get you going. You can also create your own objects for modeling your own data and creating your own functionality to meet your needs however you see fit.

Standard Objects

Label
Name
Plural Name
Description
Extensible

account

accounts

The Account Object represents a user account within an Organization.

true

org

orgs

The Organization object represents the org, itself.

true

connection

connections

Connections enable access to an object instance for a target. For more details, see Connections

false

notification

notifications

Notifications are created when persistent notifications are sent. They contain meta-data about notifications that can facilitate notification handling in client apps.

false

object

objects

The Object object contains the definitions for custom and extended Cortex objects.

false

Extending Standard Objects

You can extend standard objects by adding custom properties. You can do this via the admin UI and also directly via the Object API.

For example, if you'd like to track the most recent app login for a particular user, you might add a c_last_logged_in property that is a Date type to the Account standard object. Now, every user that registers in your app can be stored in the backend with this additional date property. You can pass in the c_last_logged_in parameter and the Medable API will know to store that field in a given Account.

You can add any number of custom properties of varying types to get the desired functionality for your application.

Custom Objects

You can extend the API by creating new custom objects and with custom properties, You can do this via the admin UI and also directly via the Object API.

Custom Cortex object and property names are prefixed with c_ to differentiate them from standard objects and properties. Additionally, custom objects are given a plural name along with the name you provide. So, for example if you create a custom objects named patient, the api name of your object will be c_patient and the plural name will be c_patients. If you were to create a custom name document property on your c_patient object, with sub string properties of first and last, then your c_patient object could look something like:

{
  "c_name": {
    "c_first": "Jane",
    "c_last": "Doe"
  }
}

Although a standard object's standard properties cannot be modified, custom properties can be added to extensible standard objects.

Suggest Edits

Organization Object

Represents the Organization itself.

 

Note

All Organization properties requiring Public access are exposed through GET to the public.

_id
String

The org identifier

access
Number

The current caller’s context access level.

apps
Document[]

The Org’s configured applications.

code*
String

The Org’s code, used to access the api, uniquely identifies the org.

configuration
Document

Org configuration settings.

connections
Reference[]

Connections associated with the Org.

created
Date

The date the context was created.

deployment
Document

Org deployment settings

favicon
File

Organization Icon

locale
String

The Org’s default locale setting.

logo
File

The Org logo.

maintenance
Boolean

True if Org is in maintenance mode.

maintenanceMessage
String

The message to show during maintenance mode.

name*
String

The Org label.

object
String

The context’s object name.

posts
Reference[]

A list of posts made in the context of the org.

registration
Document

Org registration settings.

roles
Document[]

Org’s configured roles.

schemasETag
String

Org schemas ETag

security
Document

Org security settings.

shared
Boolean

True if there are any active or pending connections for this context.

state
String

The Org state.

support
Document

Support options.

tz
String

Default timezone for the org. This helps determine UTC offset when working in scripts when a user tz is not available. The timezone must by a unique identifier for an IANA assigned zone, e.g. "US/Pacific"

updated
Date

The date the latest update was made to a context’s properties

updater
Reference

The account id of the context updater

website
String

The Org website, available for use as a variable in email templates (org.website).

{
    "_id": "5516ee1b34d8d934281699e3",
    "access": 1,
    "code": "example",
    "favicon": {
        "ETag": "31074002db56d2d6fc8fee5b05caee1c",
        "creator": "5516ee2634d8d93428169c0e",
        "location": 4,
        "mime": "image/x-icon",
        "name": "content",
        "path": "/orgs/5516ee1b34d8d934281699e3/favicon/content",
        "size": 15086,
        "state": 2
    },
    "locale": "en_US",
    "logo": {
        "ETag": "594b69d035ac27c2e69ef053082eb6a3",
        "creator": "5516ee2634d8d93428169c0e",
        "facets": [
            {
                "ETag": "5046104d05edf82e2a2c0d72118ca15b",
                "creator": "5516ee2634d8d93428169c0e",
                "height": 241,
                "location": 4,
                "mime": "image/jpeg",
                "name": "thumbnail",
                "path": "/orgs/5516ee1b34d8d934281699e3/logo/thumbnail",
                "size": 16495,
                "state": 2,
                "width": 300
            }
        ],
        "height": 500,
        "location": 4,
        "mime": "image/jpeg",
        "name": "content",
        "path": "/orgs/5516ee1b34d8d934281699e3/logo/content",
        "size": 52586,
        "state": 2,
        "width": 622
    },
    "name": "Example",
    "object": "org",
    "schemasETag": "b7fa703927702d09ada85150f475d88c"
}
Suggest Edits

Read (Public)

 

Header Auth

 Authentication is required for this endpoint.
gethttps://api.dev.medable.com/your_org_name/v2
$.ajax({
    url: "https://api.dev.medable.com/example/v2/",
    method: "GET",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}).done(function(data) {
    // ...
});
 [[MDAPIClient sharedClient] getOrgInfoWithCallback:^(MDOrg *org, MDFault *fault)
  {
     // Handle fault or process results
  }];
APIClient.sharedInstance().getPublicOrgInfo(new ObjectFaultCallback<JsonObject>()
{
    @Override
    public void call(JsonObject object, Fault fault)
    {
        // Public org's info in Json format
    }
});
A binary file was returned

You couldn't be authenticated

{
    "_id": "5516ee1b34d8d934281699e3",
    "access": 1,
    "code": "example",
    "favicon": {
        "ETag": "31074002db56d2d6fc8fee5b05caee1c",
        "creator": "5516ee2634d8d93428169c0e",
        "location": 4,
        "mime": "image/x-icon",
        "name": "content",
        "path": "/orgs/5516ee1b34d8d934281699e3/favicon/content",
        "size": 15086,
        "state": 2
    },
    "locale": "en_US",
    "logo": {
        "ETag": "594b69d035ac27c2e69ef053082eb6a3",
        "creator": "5516ee2634d8d93428169c0e",
        "facets": [
            {
                "ETag": "5046104d05edf82e2a2c0d72118ca15b",
                "creator": "5516ee2634d8d93428169c0e",
                "height": 241,
                "location": 4,
                "mime": "image/jpeg",
                "name": "thumbnail",
                "path": "/orgs/5516ee1b34d8d934281699e3/logo/thumbnail",
                "size": 16495,
                "state": 2,
                "width": 300
            }
        ],
        "height": 500,
        "location": 4,
        "mime": "image/jpeg",
        "name": "content",
        "path": "/orgs/5516ee1b34d8d934281699e3/logo/content",
        "size": 52586,
        "state": 2,
        "width": 622
    },
    "name": "Example",
    "object": "org",
    "schemasETag": "b7fa703927702d09ada85150f475d88c"
}

Path Params

your_org_name
string
required
 
Suggest Edits

Read (Full)

 

Header Auth

 Authentication is required for this endpoint.
gethttps://api.dev.medable.com/your_org_name/v2/orgs/org_id
$.ajax({
    url: "https://api.dev.medable.com/example/v2/orgs/5516ee1b34d8d934281699e3",
    method: "GET",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}).done(function(data) {
    // ...
});
[[MDAPIClient sharedClient]
 orgWithId:self.Id
 parameters:parameters
 callback:^(MDOrg* updatedOrg, MDFault *fault)
 {
   if ( [updatedOrg isKindOfClass:[wSelf class]] && fault == nil )
   {
     [wSelf updateWithInstance:updatedOrg];
   }

   if ( callback )
   {
     callback(updatedOrg, fault);
   }
 }];
Org org = APIClient.sharedInstance().getCurrentOrg();

// or:

APIClient.sharedInstance().getOrg(
        new ObjectId("orgId here"),
        null,
        new ObjectFaultCallback<Org>()
        {
            @Override
            public void call(Org org, Fault fault)
            {
                // Handle fault or process results
            }
        }
);
A binary file was returned

You couldn't be authenticated

{
    "_id": "5516ee1b34d8d934281699e3",
    "access": 1,
    "code": "example",
    "favicon": {
        "ETag": "31074002db56d2d6fc8fee5b05caee1c",
        "creator": "5516ee2634d8d93428169c0e",
        "location": 4,
        "mime": "image/x-icon",
        "name": "content",
        "path": "/orgs/5516ee1b34d8d934281699e3/favicon/content",
        "size": 15086,
        "state": 2
    },
    "locale": "en_US",
    "logo": {
        "ETag": "594b69d035ac27c2e69ef053082eb6a3",
        "creator": "5516ee2634d8d93428169c0e",
        "facets": [
            {
                "ETag": "5046104d05edf82e2a2c0d72118ca15b",
                "creator": "5516ee2634d8d93428169c0e",
                "height": 241,
                "location": 4,
                "mime": "image/jpeg",
                "name": "thumbnail",
                "path": "/orgs/5516ee1b34d8d934281699e3/logo/thumbnail",
                "size": 16495,
                "state": 2,
                "width": 300
            }
        ],
        "height": 500,
        "location": 4,
        "mime": "image/jpeg",
        "name": "content",
        "path": "/orgs/5516ee1b34d8d934281699e3/logo/content",
        "size": 52586,
        "state": 2,
        "width": 622
    },
    "name": "Example",
    "object": "org",
    "schemasETag": "b7fa703927702d09ada85150f475d88c"
}

Path Params

your_org_name
string
required
org_id
string
required
 

Header Auth

 Authentication is required for this endpoint.
puthttps://api.dev.medable.com/your_org_name/v2/orgs/org_id
$.ajax({
    url: "https://api.dev.medable.com/example/v2/orgs/5516ee1b34d8d934281699e3/c_4providers",
    method: "PUT",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    },
    data: [
    -5,
    -4,
    -3,
    -2,
    -1,
    0,
    11,
    22,
    33,
    44,
    55
]
}).done(function(data) {
    // ...
});
NSDictionary *body = @{ @"c_providers": @{ @"data": @[ @(-5), @(-4), @(-3), @(-2), @(-1), @(0), @(11), @(22), @(33), @(44), @(55) ] } };

[[MDAPIClient sharedClient]
 updateOrgWithId:[MDObjectId objectIdWithString:@"5516ee1b34d8d934281699e3"]
 body:body
 callback:^(MDOrg * _Nullable editedObject, MDFault * _Nullable fault)
 {

 }];
Body body = new Body();

JsonObject jsonContent = APIClient.sharedInstance().getGsonParser()
        .parse("{ \"c_providers\": { \"data\": [ -5, -4, -3, -2, -1, 0, 11, 22, 33, 44, 55 ] } }")
        .getAsJsonObject();

FastBodyProperty fastProp = new FastBodyProperty(jsonContent);
body.addProperty(fastProp);

APIClient.sharedInstance().updateOrg(
        new ObjectId("5516ee1b34d8d934281699e3"),
        body,
        new ObjectFaultCallback<Org>()
        {
            @Override
            public void call(Org editedOrg, Fault fault)
            {

            }
        }
);
A binary file was returned

You couldn't be authenticated

{
    "hasMore": false,
    "object": "list",
    "data": [-4, -3, -2, -1, 0, 11, 22, 33, 44, 55]
}

Path Params

your_org_name
string
required
org_id
string
required
 

The Organization settings can only be updated by an Administrator. Because the Org is public, it is possible to add a custom property to allow those with other roles (or no roles) to update it. To demonstrate, the following property has been added to the Organization in the example request to the right, and all Providers given access to push elements onto the c_4providers array.

Header Auth

 Authentication is required for this endpoint.
patchhttps://api.dev.medable.com/your_org_name/v2/orgs/org_id
$.ajax({
    url: "https://api.dev.medable.com/example/v2/orgs/586eb9ef64129a5f3631a0ca",
    method: "PATCH",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    },
    data: { 
      	"op": "push", 
      	"path": "/configuration/email/locationBypass", 
      	"value": "john@medable.com" 
    }
}).done(function(data) {
    // ...
});
A binary file was returned

You couldn't be authenticated

{
    "_id": "5810f10e6d66738355843d7d",
    "access": 6,
    "bundleVersion": 0,
    "c_pin": 9955,
    "code": "kevinsresearch",
    "configuration": {
        "email": {
            "from": "",
            "fromName": "",
            "locationBypass": [
              	"polly@medable.com",
                "john@medable.com"
            ],
            "providerVerifications": [],
            "registrations": [],
            "replyTo": ""
        },
        "sms": {
            "internalOverCustom": false,
            "numbers": []
        },
        "urls": {
            "activateAccount": "",
            "connection": "",
            "createPassword": "",
            "resetPassword": "",
            "verifyAccount": ""
        }
    },
    "created": "2016-10-26T18:08:14.955Z",
    "locale": "en_US",
    "maintenance": false,
    "maintenanceMessage": "",
    "name": "KevinsResearch",
    "object": "org",
    "registration": {
        "activationRequired": false,
        "allow": false,
        "allowProviders": false,
        "bypassAccountVerification": false,
        "invitationRequired": false,
        "manualProviderVerification": false
    },
    "schemasETag": "17195523920a45e20174cf133088f150",
    "security": {
        "unauthorizedAccess": {
            "lockAttempts": 5,
            "lockDuration": 15
        }
    },
    "shared": false,
    "state": "enabled",
    "updated": "2017-06-06T14:16:30.653Z",
    "updater": {
        "_id": "5810f1106d66738355844001",
        "object": "account",
        "path": "/accounts/5810f1106d66738355844001"
    },
    "website": "https://app.medable.com/kevinsresearch/"
}

Path Params

your_org_name
string
required
org_id
string
required

Body Params

op
string
path
string
value
string
 
Suggest Edits

Account Object

The Account Object represents a user account within an Organization.

 

_id
ObjectId

The account identifier.

access
Number

The current caller's context access level.

activationRequired
Boolean

True if the account must be activated before use. Dependant on Org settings.

age
Number

The age of the account holder (based on the dob property).

connections
Reference[]

Connections associated with the Account.

created
Date

The date the context was created.

dob
Date

Account holder date of birth.

email*
String

The email address for the account and must be unique within the Org.

favorite
Boolean

Tags the context as a favorite, which can then be filtered using the API.

gender
String

Account holder gender.

image
File

The account profile image.

inherited_roles
ObjectId[]

Any roles that are inherited from my current role. If my current role has no sub-roles then this is an empty array.

key
Document

A fingerprint and secret, re-generated on password change. Useful for client-side PHI encryption/caching scenarios, it is available to the account holder for the life of an authenticated session.

mobile
String

The mobile number of the account holder. This number should be capable of receiving SMS messages and must be in E.164 format.

name
Document

Name of the account holder (split into first and last names).

object
String

The context’s object name.

preferences
Document

The account preferences.

profile
Document

The account profile.

roles
ObjectId[]

Account roles (e.g. Provider, Administrator, Developer). Accounts can have more than one role.

shared
Boolean

True if there are any active or pending connections for this context.

state
String

Current state for the account. (e.g. unverified, verified)

tz
String

Timezone for the account. This helps determine UTC offset when working in scripts. The timezone must by a unique identifier for an IANA assigned zone, e.g. "US/Pacific"

updated
Date

The date the latest update was made to a context’s properties

updater
Reference

The account id of the context updater

{
    "_id": "54c66edac364f2201b78c34e",
    "access": 6,
    "dob": "1975-01-26",
    "email": "john.smith@example.com",
    "favorite": false,
    "gender": "m",
    "key": {
        "fingerprint": "094be6f0-a57b-11e4-9323-d35446f5af36",
        "secret": "P07uqKLlXDWjj3s85TGJt4BXSuSCFlpx"
    },
    "locale": "en_US",
    "locked": false,
    "mobile": "15551234567",
    "name": {
        "first": "John",
        "last": "Smith"
    },
    "object": "account",
    "preferences": {
        "notifications": [
            {
                "label": "Custom Notifier",
                "name": "c_notifier",
                "_id": "56cbfddcba9ef5257bf48513",
                "endpoints": [
                    {
                        "_id": "456e64706f696e7420536d73",
                        "enabled": false,
                        "label": "SMS",
                        "name": "sms"
                    },
                    {
                        "_id": "456e64706f696e7420456d6c",
                        "enabled": true,
                        "label": "Email",
                        "name": "email"
                    }
                ]
            }
        ]
    },
    "profile": {
        "provider": {
            "affiliation": "None",
            "license": {
                "number": "777",
                "state": "Alabama"
            },
            "npi": "798798798",
            "specialty": "Allergy and Immunology",
            "state": "processing",
            "visibility": {
                "provider": false,
                "public": false
            }
        }
    },
    "roles": [
        "000000000000000000000005"
    ],
    "shared": false,
    "state": "verified",
    "updated": "2015-03-12T18:47:34.010Z"
}
Suggest Edits

List

Retrieve all accounts

 

Header Auth

 Authentication is required for this endpoint.
gethttps://api.dev.medable.com/your_org_name/v2/accounts
$.ajax({
    url: "https://api.dev.medable.com/example/v2/accounts?paths[]=name",
    method: "GET",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}).done(function(data) {
    // ...
});
MDAPIParameters* parameters = [MDAPIParameterFactory parametersWithLimitPaths:@[ kNameKey ]];

[[MDAPIClient sharedClient]
 listObjectsWithContext:kPluralAccountContext
 parameters:parameters
 callback:^(NSArray *objects, NSNumber *hasMore, MDFault *fault)
 {
     if (fault)
     {
         // Fault handling
     }
     else
     {
         // All good. You should synchronize the current user's account object
     }
 }];
APIParameters parameters = APIParameterFactory.parametersWithLimitPaths(null, Constants.kName);

APIClient.sharedInstance().listObjects(
        Constants.kAccounts,
        parameters,
        new ObjectsListCallback<ObjectInstance>()
        {
            @Override
            public void call(List<ObjectInstance> objects, boolean hasMore, Fault fault)
            {
                if (null != fault)
                {
                    // Fault handling
                }
                else
                {
                    // All good. You should synchronize the current user's account object
                }
            }
        }
);
A binary file was returned

You couldn't be authenticated

{
    "data": [
        {
            "_id": "5525fc2db7995d2c2807632a",
            "object": "account",
            "name": {
                "first": "Charles",
                "last": "Best"
            }
        },
        {
            "_id": "552352a4ea05b030066583fc",
            "object": "account",
            "name": {
                "first": "Charles",
                "last": "Best"
            }
        }
    ],
    "hasMore": false,
    "object": "list"
}

Path Params

your_org_name
string
required
 
Suggest Edits

Read

Retrieve an account

 

Header Auth

 Authentication is required for this endpoint.
gethttps://api.dev.medable.com/your_org_name/v2/accounts/account_id
$.ajax({
    url: "https://api.dev.medable.com/example/v2/accounts/5525fc2db7995d2c2807632a",
    method: "GET",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}).done(function(data) {
    // ...
});
[[MDAPIClient sharedClient]
 objectWithContext:kPluralAccountContext
 objectId:@"5525fc2db7995d2c2807632a"
 parameters:nil
 callback:^(id object, MDFault *fault)
 {
     if (fault)
     {
         // Fault handling
     }
     else if ( [object isKindOfClass:[MDAccount class]] && fault == nil )
     {
         // All good
     }
 }];
APIClient.sharedInstance().getObject(
  Constants.kAccounts,
  new ObjectId("5525fc2db7995d2c2807632a"),
  null,
  new ObjectFaultCallback<ObjectInstance>()
  {
    @Override
    public void call(ObjectInstance object, Fault fault)
    {
      if (null != fault)
      {
        // Fault handling
      }
      else if (object instanceof Account && fault == null)
      {
        // All good
      }
    }
  }
);
A binary file was returned

You couldn't be authenticated

{
    "_id": "5525fc2db7995d2c2807632a",
    "access": 2,
    "favorite": false,
    "image": {
        "ETag": "594b69d035ac27c2e69ef053082eb6a3",
        "creator": "5525fc2db7995d2c2807632a",
        "facets": [
            {
                "ETag": "047fb43a1389f6a00d06fdbbe8780a0c",
                "creator": "5525fc2db7995d2c2807632a",
                "height": 160,
                "location": 4,
                "mime": "image/jpeg",
                "name": "thumbnail",
                "path": "/accounts/5525fc2db7995d2c2807632a/image/thumbnail",
                "size": 7823,
                "state": 2,
                "width": 160
            }
        ],
        "height": 500,
        "location": 4,
        "mime": "image/jpeg",
        "name": "content",
        "path": "/accounts/5525fc2db7995d2c2807632a/image/content",
        "size": 52586,
        "state": 2,
        "width": 622
    },
    "name": {
        "first": "Charles",
        "last": "Best"
    },
    "object": "account",
    "shared": true,
    "updated": "2015-04-15T16:56:32.052Z",
    "updater": {
        "_id": "000000000000000000000002",
        "object": "account",
        "path": "/accounts/000000000000000000000002"
    }
}

Path Params

your_org_name
string
required
account_id
string
required
 
Suggest Edits

Current User

 

Header Auth

 Authentication is required for this endpoint.
gethttps://api.dev.medable.com/your_org_name/v2/accounts/me
$.ajax({
    url: "https://api.dev.medable.com/example/v2/accounts/me",
    method: "GET",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}).done(function(data) {
    // ...
});
[[MDAPIClient sharedClient]
 currentAccount:^(MDAccount* account, MDFault* fault)
 {
     if (fault)
     {
         // Fault handling
     }
     else
     {

     }
 }];
APIClient.sharedInstance().currentAccount(
        new ObjectFaultCallback<Account>()
        {
            @Override
            public void call(Account account, Fault fault)
            {
                if (null != fault)
                {
                    // Fault handling
                }
                else
                {

                }
            }
        }
);
A binary file was returned

You couldn't be authenticated

{
    "_id": "552352a4ea05b030066583fc",
    "access": 6,
    "dob": "1899-02-27",
    "email": "charles.best@example.org",
    "favorite": false,
    "gender": "m",
    "key": {
        "fingerprint": "69521070-dcd8-11e4-98e9-c5a28d7729c2",
        "secret": "cUdg8LCspNtSVDPCdr281oD6c2PO0EVW"
    },
    "locale": "en_US",
    "locked": false,
    "mobile": "16505555555",
    "name": {
        "first": "Charles",
        "last": "Best"
    },
    "object": "account",
    "roles": [],
    "shared": false,
    "state": "unverified"
}

Path Params

your_org_name
string
required
 
Suggest Edits

Register

Account registration

 

Header Auth

 Authentication is required for this endpoint.
posthttps://api.dev.medable.com/your_org_name/v2/accounts/register
$.ajax({
    url: "https://api.dev.medable.com/example/v2/accounts/register",
    method: "POST",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    },
    data: {
    "name": {
        "first": "Charles",
        "last": "Best"
    },
    "email": "charles.best@example.org",
    "gender": "m",
    "dob": "1899-02-27",
    "mobile": "1-650-555-5555",
    "password": "Thanks for the break, Banting!"
}
}).done(function(data) {
    // ...
});
 [[MDAPIClient sharedClient]
  registerAccountWithFirstName:@"Charles"
  lastName:@"Best"
  email:@"charles.best@example.org"
  mobile:@"1-650-555-5555"
  password:@"Thanks for the break, Banting!"
  gender:@"m"
  dob:[MDDateUtilities dateFromString:@"1899-02-27"]
  role:nil
  profileInfo:nil
  thumbImage:nil
  callback:^(MDAccount* account, MDFault *fault)
  {
      if ( fault != nil)
      {
          // Handle the error (e.g. show alert with fault.message)
      }
      else
      {
          // Check whether email verification is required before authentication
          BOOL requiresActivation = [account activationRequired] ? [[account activationRequired] boolValue] : NO;

          // Handle the case when requiresActivation == YES here
      }
  }];
Date dobDate = new Date();

AccountInfo accountInfo = AccountInfo.Builder
        .infoType(AccountInfoType.Registration)
        .firstName("Charles")
        .lastName("Best")
        .email("charles.best@example.org")
        .mobile("1-650-555-5555")
        .password("Thanks for the break, Banting!")
        .gender(Gender.Male)
        .dob(dobDate)
        .build();

APIClient.sharedInstance().registerAccount(
        accountInfo,
        null,
        null,
        new ObjectFaultCallback<Account>()
        {
            @Override
            public void call(Account account, Fault fault)
            {
                if (fault != null)
                {
                    // Handle the error (e.g. show alert with fault.message)
                }
                else
                {
                    // Check whether activation is required before authentication
                    boolean requiresActivation = account.getActivationRequired();

                    // Handle the case when requiresActivation == true here
                }
            }
        });
A binary file was returned

You couldn't be authenticated

{
    "_id": "552352a4ea05b030066583fc",
    "access": 6,
    "dob": "1899-02-27",
    "email": "charles.best@example.org",
    "favorite": false,
    "gender": "m",
    "key": {
        "fingerprint": "69521070-dcd8-11e4-98e9-c5a28d7729c2",
        "secret": "cUdg8LCspNtSVDPCdr281oD6c2PO0EVW"
    },
    "locale": "en_US",
    "locked": false,
    "mobile": "16505555555",
    "name": {
        "first": "Charles",
        "last": "Best"
    },
    "object": "account",
    "roles": [],
    "shared": false,
    "state": "unverified"
}

Path Params

your_org_name
string
required

Body Params

name
object
required
 
name.first
string
name.last
string
email
string
required

This is later used with the password to log the user in

mobile
string
required

In E.164 format

password
string
required

Must meet org password strength requirements

dob
date

YYYY-MM-DD

gender
string

"m" or "f"

tz
string

The timezone for the user

token
string

Invite/connection token (if applicable)

 

Header Auth

 Authentication is required for this endpoint.
posthttps://api.dev.medable.com/your_org_name/v2/accounts/login
$.ajax({
    url: "https://api.dev.medable.com/example/v2/accounts/login",
    method: "POST",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    },
    data: {
    "email": "james@example.com",
    "password": "this is not my passphrase",
    "location": {
        "verificationToken": "123456",
        "locationName": "New Orleans",
        "singleUse": true
    }
}
}).done(function(data) {
    // ...
});
[[MDAPIClient sharedClient]
 authenticateSessionWithEmail:@"james@example.com"
 password:@"this is not my passphrase"
 verificationToken:@"123456"
 singleUse:YES
 callback:^(MDAccount *localUser, MDFault *fault)
 {
     if (!fault && localUser)
     {

     }
     else
     {
         if (fault)
         {
             if ([fault.code isEqual:kMDAPIErrorNewLocation] ||
                 [fault.code isEqual:kMDAPIErrorUnverifiedLocation])
             {
                 // Device verification handling
             }
             else
             {
                 // Other faults handling
             }
         }
         else
         {
             // Login failed without MDFault (i.e. time out, etc)
         }
     }
 }];

APIClient.sharedInstance().login(
        "james@example.com",
        "this is not my passphrase",
        "123456",
        true,
        new ObjectFaultCallback<Account>()
        {
            @Override
            public void call(Account localUser, Fault fault)
            {
                if (null == fault && null != localUser)
                {

                }
                else
                {
                    if (null == fault)
                    {
                        if (fault.getCode().equals(Constants.kFaultNewLocation) ||
                                fault.getCode().equals(Constants.kFaultUnverifiedLocation))
                        {
                            // Device verification handling
                        }
                        else
                        {
                            // Other faults handling
                        }
                    }
                    else
                    {
                        // Login failed without Fault (i.e. time out, etc)
                    }
                }
            }
        }
);
A binary file was returned

You couldn't be authenticated

{
    "_id": "552352a4ea05b030066583fc",
    "access": 6,
    "dob": "1899-02-27",
    "email": "charles.best@example.org",
    "favorite": false,
    "gender": "m",
    "key": {
        "fingerprint": "69521070-dcd8-11e4-98e9-c5a28d7729c2",
        "secret": "cUdg8LCspNtSVDPCdr281oD6c2PO0EVW"
    },
    "locale": "en_US",
    "locked": false,
    "mobile": "16505555555",
    "name": {
        "first": "Charles",
        "last": "Best"
    },
    "object": "account",
    "roles": [],
    "shared": false,
    "state": "unverified"
}

Path Params

your_org_name
string
required

Body Params

email
string
required
password
string
required
location
object
 
location.verificationToken
string

6 digit verification token sent to user's mobile device for 2FA

location.locationName
string

If you want to associate a string with a given authorized access point

location.singleUse
boolean

The equivalent of "Remember Me" checkbox common in login options.

 
Suggest Edits

Logout

Invalidate the currently authenticated session.

 

Header Auth

 Authentication is required for this endpoint.
posthttps://api.dev.medable.com/your_org_name/v2/accounts/me/logout
$.ajax({
    url: "https://api.dev.medable.com/example/v2/accounts/me/logout",
    method: "POST",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}).done(function(data) {
    // ...
});
[[MDAPIClient sharedClient] logout:^(MDFault* fault)
{
    if (fault)
    {
        // Fault handling here
    }
}];
APIClient.sharedInstance().logout(new FaultCallback()
{
    @Override
    public void call(Fault fault)
    {
        if (fault != null)
        {
            // Fault handling here
        }
    }
});
A binary file was returned

You couldn't be authenticated

{
    "object": "result",
    "data": true
}

Path Params

your_org_name
string
required
 
Suggest Edits

Request Password Reset

Request a password reset via email

 

Header Auth

 Authentication is required for this endpoint.
posthttps://api.dev.medable.com/your_org_name/v2/accounts/request-password-reset
$.ajax({
    url: "https://api.dev.medable.com/example/v2/accounts/request-password-reset",
    method: "POST",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    },
    data: {
    "email": "charles.best@medable.com"
}
}).done(function(data) {
    // ...
});
[[MDAPIClient sharedClient]
 requestPasswordResetWithEmail:@"charles.best@medable.com"
 callback:^(MDFault* fault)
 {
     if (fault)
     {
         // Fault handling
     }
     else
     {

     }
 }];
APIClient.sharedInstance().requestPasswordReset(
        "charles.best@medable.com",
        new FaultCallback()
  {
    @Override
    public void call(Fault fault)
    {
      if (null != fault)
      {
        // Fault handling
      }
      else
      {

      }
    }
  });
A binary file was returned

You couldn't be authenticated

{
    "object":"result",
    "data":true
}

Path Params

your_org_name
string
required

Body Params

email
string
required
 

This endpoint would typically be used when a user is trying to login but cannot remember his/her password. They can simply enter their email address associated with the account (which gets passed into this endpoint) and an email will be automatically generated by Medable with the proper link to set a new password.

Example:

  1. Request Password Reset gets called
  2. Medable sends the email with a one-time secure reset password token (string)
  3. The user opens that email and clicks a link which has this token as a url parameter
  4. User gets navigated to a Medable web GUI for setting the new password

Note

You can override the destination link in part 4 to be your own page on your own domain for app look and feel consistency.

Suggest Edits

Update My Password

Update the currently logged in user's password directly through the API

 

Header Auth

 Authentication is required for this endpoint.
posthttps://api.dev.medable.com/your_org_name/accounts/me/update-password
$.ajax({
    url: "https://api.dev.medable.com/example/v2/accounts/me/update-password",
    method: "POST",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    },
    data: {
    "current": "this is not my passphrase",
    "password": "correct horse battery staple"
}
}).done(function(data) {
    // ...
});
[[MDAPIClient sharedClient]
 updatePasswordWithCurrentPassword:@"this is not my passphrase"
 newPassword:@"correct horse battery staple"
 callback:^(MDFault *fault)
 {
     if (fault)
     {
         // Fault handling
     }
     else
     {

     }
 }];
APIClient.sharedInstance().updatePassword(
  "this is not my passphrase",
  "correct horse battery staple",
  new FaultCallback()
  {
    @Override
    public void call(Fault fault)
    {
      if (null != fault)
      {
        // Fault handling
      }
      else
      {

      }
    }
  }
);
A binary file was returned

You couldn't be authenticated

{
    "object": "result",
    "data": {
        "fingerprint": "b8342060-e409-11e4-bcc2-c71dd7c9f996",
        "secret": "CO6PrBDwrNnXdIizD2LasmNHnpJIw8Xd"
    }
}

Path Params

your_org_name
string
required

Body Params

current
string
required

this is the old (current) password

password
string
required

this is the new password

 

This endpoint would typically be used for a currently logged in user who wants to change his/her password directly from your app without having to go through the email password reset flow.

Suggest Edits

Update Password (Token)

 

Header Auth

 Authentication is required for this endpoint.
posthttps://api.dev.medable.com/your_org_name/v2/accounts/reset-password
$.ajax({
    url: "https://api.dev.medable.com/example/v2/accounts/reset-password",
    method: "POST",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    },
    data: {
    "token": "kPBg3AACpwTzhiOpUTz2i2koJqqot70M",
    "password": "here's a new passphrase!"
}
}).done(function(data) {
    // ...
});
[[MDAPIClient sharedClient]
 passwordResetWithToken:@"kPBg3AACpwTzhiOpUTz2i2koJqqot70M"
 password:@"here's a new passphrase!"
 callback:^(MDFault *fault)
 {
     if (fault)
     {
         // Fault handling
     }
     else
     {

     }
 }];
APIClient.sharedInstance().resetPassword(
        "kPBg3AACpwTzhiOpUTz2i2koJqqot70M",
        "here's a new passphrase!",
        new FaultCallback()
        {
            @Override
            public void call(Fault fault)
            {
                if (null != fault)
                {
                    // Fault handling
                }
                else
                {

                }
            }
        }
);
A binary file was returned

You couldn't be authenticated

{
    "object":"result",
    "data":true
}

Path Params

your_org_name
string
required

Body Params

password
string

The new password you'd like to set for this account

token
string

The one-time token that was generated for this password change

 

This endpoint would typically be used if you wanted to build a custom page that is linked in the email reset.

Example:

  1. Request Password Reset gets called
  2. Medable sends the email with a one-time secure reset password token (string)
  3. The user opens that email and clicks a link which has this token as a url parameter
  4. User gets navigated to your web app GUI for setting the new password
  5. You then call this endpoint (Reset Password) with the token passed in from the email
Suggest Edits

Verify Email From Token

 

Header Auth

 Authentication is required for this endpoint.
posthttps://api.dev.medable.com/your_org_name/v2/token
$.ajax({
    url: "https://api.dev.medable.com/example/v2/accounts/lBMSJWtqKVdx8Z888syX6axpCk2j7eYm",
    method: "POST",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}).done(function(data) {
    // ...
});
[[MDAPIClient sharedClient]
 activateAccountWithToken:@"lBMSJWtqKVdx8Z888syX6axpCk2j7eYm"
 callback:^(MDFault *fault)
 {
     if (fault)
     {
         // Fault handling
     }
     else
     {

     }
 }];
APIClient.sharedInstance().activateAccount(
        "lBMSJWtqKVdx8Z888syX6axpCk2j7eYm",
  new FaultCallback()
  {
    @Override
    public void call(Fault fault)
    {
      if (null != fault)
      {
        // Fault handling
      }
      else
      {

      }
    }
  }
);
A binary file was returned

You couldn't be authenticated

{
    "object": "result",
    "data": "5525fc2db7995d2c2807632a" 
  	// id of verified account
}

Path Params

token
string
required

The email verification process generates a token that can be passed in to mark an email as verified.

your_org_name
string
required
 
Suggest Edits

Resend Email Verification

Resend currently logged in user's email verification

 

Header Auth

 Authentication is required for this endpoint.
posthttps://api.dev.medable.com/your_org_name/v2/accounts/me/resend-verification
$.ajax({
    url: "https://api.dev.medable.com/example/v2/accounts/me/resend-verification",
    method: "POST",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}).done(function(data) {
    // ...
});
[[MDAPIClient sharedClient]
 resendAccountVerificationWithCallback:^(MDFault *fault)
 {
     if (fault)
     {
         if ([fault.code isEqualToString:kMDAPIErrorAccountAlreadyVerified])
         {
             // The account is already verified. It's recommented you synchronize the current user's account object
         }
         else
         {
             // Other faults hanlding
         }
     }
     else
     {
     }
 }];
APIClient.sharedInstance().resendAccountVerification(
        new FaultCallback()
  {
    @Override
    public void call(Fault fault)
    {
      if (null != fault)
      {
        if (fault.getCode().equals(Constants.kFaultLocationAlreadyVerified))
        {
          // The account is already verified. It's recommented you synchronize the current user's account object
        }
        else
        {
          // Other faults handling
        }
      }
      else
      {
      }
    }
  }
);
A binary file was returned

You couldn't be authenticated

{
    "object": "result",
    "data": true
}
{
    "object":"result",
    "data": {
        "object": "fault",
        "name": "error",
        "code": "kExists",
        "status": 409,
        "reason": "Account already verified"
    }
}

Path Params

your_org_name
string
required
 
Suggest Edits

Update

To modify a property on an Account object

 

Header Auth

 Authentication is required for this endpoint.
puthttps://api.dev.medable.com/your_org_name/v2/accounts/account_id
$.ajax({
    url: "https://api.dev.medable.com/example/v2/accounts/586eb9ef64129a5f3631a0ca",
    method: "PUT",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    },
    data: {
    "name": {
        "first":"Bob",
        "last":"Dole"
    }
}
}).done(function(data) {
    // ...
});
MDProfileInfo* profileInfo = [MDProfileInfo profileInfoWithSpecialty:@"Vascular Surgery"
                                                         affiliation:nil
                                                                 npi:@"7878766774"
                                                        licenseState:nil
                                                       licenseNumber:nil];

[[MDAPIClient sharedClient]
 updateAccountWithID:[MDObjectId objectIdWithString:@"5525fc2db7995d2c2807632a"]
 firstName:nil
 lastName:nil
 gender:nil
 mobile:nil
 dob:nil
 profileInfo:profileInfo
 favorite:nil
 preferences:nil
 image:nil
 customPropValues:nil
 finishBlock:^(MDAccount *account, MDFault *fault)
 {
     if (fault)
     {
         // Fault handling
     }
     else
     {
         // All good. You should synchronize the current user's account object
     }
 }];
AccountInfo updateAccountInfo = AccountInfo.Builder
        .infoType(AccountInfoType.Update)
        .specialty("Vascular Surgery")
        .npi("7878766774")
        .build();

APIClient.sharedInstance().updateAccount(
        new ObjectId("5525fc2db7995d2c2807632a"),
        updateAccountInfo,
        null,
        null,
        null,
        null,
        new ObjectFaultCallback<Account>()
        {
            @Override
            public void call(Account object, Fault fault)
            {
                if (null != fault)
                {
                    // Fault handling
                }
                else
                {
                    // All good. You should synchronize the current user's account object
                }
            }
        }
);
A binary file was returned

You couldn't be authenticated

{
    "_id": "586eb9ef64129a5f3631a0ca",
    "access": 6,
    "created": "2016-01-05T21:26:07.292Z",
    "email": "john@medable.com",
    "favorite": false,
    "gender": "m",
    "inherited_roles": [
        "000000000000000000000007",
        "000000000000000000000006"
    ],
    "key": {
        "fingerprint": "a15aecd0-d394-11e6-9754-5f93dce3d489",
        "secret": "fDQEdMnfqxmFvCBtHpl7FWPnxcUTaBOl"
    },
    "locale": "en_US",
    "locked": false,
    "mobile": "+12223334444",
    "name": {
        "first": "Bob",
        "last": "Dole"
    },
    "object": "account",
    "roles": [
        "000000000000000000000004"
    ],
    "shared": false,
    "state": "verified",
    "updated": "2016-06-06T14:07:20.299Z",
    "updater": {
        "_id": "586eb9ef64129a5f3631a0ca",
        "object": "account",
        "path": "/accounts/586eb9ef64129a5f3631a0ca"
    }
}

Path Params

your_org_name
string
required
account_id
string
required

Body Params

name
object
 
name.first
string
name.last
string
mobile
string
dob
string
gender
string
any account property
mixed type
 

Email cannot be changed

Due to security reasons, we do not allow modifying of the email address of a given account.

Suggest Edits

Update

To modify a property on an Account object via PATCH

 

Header Auth

 Authentication is required for this endpoint.
patchhttps://api.dev.medable.com/your_org_name/v2/accounts/account_id
$.ajax({
    url: "https://api.dev.medable.com/example/v2/accounts/586eb9ef64129a5f3631a0ca",
    method: "PATCH",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    },
    data: { 
      	"op": "push", 
      	"path": "/roles", 
      	"value": "587012227d67efea0843fa80" 
    }
}).done(function(data) {
    // ...
});
A binary file was returned

You couldn't be authenticated

{
    "_id": "586eb9ef64129a5f3631a0ca",
    "access": 6,
    "created": "2016-01-05T21:26:07.292Z",
    "email": "john@medable.com",
    "favorite": false,
    "gender": "m",
    "inherited_roles": [
        "000000000000000000000007",
        "000000000000000000000006"
    ],
    "key": {
        "fingerprint": "a15aecd0-d394-11e6-9754-5f93dce3d489",
        "secret": "fDQEdMnfqxmFvCBtHpl7FWPnxcUTaBOl"
    },
    "locale": "en_US",
    "locked": false,
    "mobile": "+12223334444",
    "name": {
        "first": "John",
        "last": "Smith"
    },
    "object": "account",
    "roles": [
        "000000000000000000000004",
        "587012227d67efea0843fa80"
    ],
    "shared": false,
    "state": "verified",
    "updated": "2016-06-06T14:01:08.699Z",
    "updater": {
        "_id": "586eb9ef64129a5f3631a0ca",
        "object": "account",
        "path": "/accounts/586eb9ef64129a5f3631a0ca"
    }
}

Path Params

your_org_name
string
required
account_id
string
required

Body Params

op
string
path
string
value
string
 
Suggest Edits

Connections Object

 

Connection enable access to objects. Once connected, each Object has a number of feeds that can be read and posted to, depending on configured access. Each object property has a minimum required CRUD access level. These are listed in the property table for each object.

Those with Share access to an object can invite others to connect. The level of access you can grant to those you invite depends on the type of object and the level of access you have. We call this the Share Chain.

To disconnect from an object, simply call the Delete route. To remove others from a context, the caller must have Share access to the context for which the connection was created and have more access than the user you are removing. These basic rules apply across all objects.

For more details on using connections, see Using Connections

_id
String

The connection identifier

access
Number

The access level granted by the connection. In the case of an ownership transfer, the access level is the object’s default owner access. An objects share chain or share ACL defines what access levels can be granted and by whom.

roles
ObjectId Array

The instance roles granted by the connection. An objects share ACL defines what roles can be granted and by whom.

context
Reference

The connection context. When expanded, imparts the connection’s access level to the caller.

contextSource
String

A dot syntax property path context in the invitation context. For example, when the account property of the Patient File is set, the resulting Connection “contextSource” is set to “account”. This enables clients to discern the nature of the Connection. In the case of Patient File, “account” means the target is being asked to act as the patient.

created
Date

The date the connection was initiated.

creator
Reference

The account id of the connection creator. Expansion paths are fixed at name an image; The caller can only retrieve the connection creator’s name and profile image.

expiresAt
Date

For pending connections. the time at which the connection request will expire.

object
String

The context’s object name.

state
Number

The connection state (Pending: 0, Active: 1).

target
Document

The connection target recipient. The email property will only be present if the connection was created using an email address. Conversely, the account property will only be present if the connection was created using an account id. The name property will only be present if the connection creator added one.

account
Reference

Optional account identifier. A connection can be created using the account identifier is it is known.

token
String

The connection token, only visible to the target.

usesRemaining
Number

Defaults to null. The number of times the connection can be loaded before it expires.

"_id": "5524165d65a7158820f4c022",
"access": 4,
"context": {
  "_id": "5519c01aae2fd2b02915c81f",
  "object": "c_example",
  "path": "/c_examples/5519c01aae2fd2b02915c81f"
},
"created": "2015-04-07T17:39:41.000Z",
"creator": {
  "_id": "5516ee2634d8d93428169c0e",
  "object": "account",
  "path": "/accounts/5516ee2634d8d93428169c0e"
},
"expiresAt": "2015-04-14T17:39:41.246Z",
"object": "connection",
"state": 0,
"target": {
  "email": "fred.banting@example.org",
  "name": {
    "first": "Frederick",
    "last": "Banting"
  }
}

Header Auth

 Authentication is required for this endpoint.
gethttps://api.dev.medable.com/your_org_name/v2/connections
$.ajax({
    url: "https://api.dev.medable.com/example/v2/connections?paths[]=state&paths[]=context",
    method: "GET",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}).done(function(data) {
    // ...
});
MDAPIParameters* parameters = [MDAPIParameterFactory parametersWithLimitPaths:@[ kStateKey, kContextKey ]];

[[MDAPIClient sharedClient]
 listConnectionsWithParameters:parameters
 callback:^(NSArray *connections, NSNumber *hasMore, MDFault *fault)
 {
     if (fault)
     {
         // Fault handling
     }
 }];
APIParameters parameters = APIParameterFactory.parametersWithLimitPaths(null, Constants.kState, Constants.kContext);

APIClient.sharedInstance().listConnections(
        parameters,
        new ObjectsListCallback<Connection>()
        {
            @Override
            public void call(List<Connection> connections, boolean hasMore, Fault fault)
            {
                if (null != fault)
                {
                    // Fault handling
                }
            }
        }
);
A binary file was returned

You couldn't be authenticated

{
    "data": [
        {
            "_id": "590a1d064966420100589cb3",
            "access": 4,
            "context": {
                "_id": "5784858f46b0104165713b93",
                "object": "c_prescription",
                "path": "/c_prescriptions/5784858f46b0104165713b93"
            },
            "contextSource": null,
            "created": "2017-05-03T18:10:14.812Z",
            "creator": {
                "_id": "5771495a1d0c03a53ce83f1a",
                "object": "account",
                "path": "/accounts/5771495a1d0c03a53ce83f1a"
            },
            "expiresAt": "2017-05-10T18:10:14.813Z",
            "object": "connection",
            "state": 0,
            "target": {
                "email": "john.smith@example.org",
                "name": {
                    "first": "John",
                    "last": "Smith"
                }
            }
        }
    ],
    "hasMore": false,
    "object": "list"
}

Path Params

your_org_name
string
required
 
State
Meaning

0

Connection has not yet been accepted by invitee

1

Connection has been accepted by invitee

Header Auth

 Authentication is required for this endpoint.
gethttps://api.dev.medable.com/your_org_name/v2/connections/connection_id
$.ajax({
    url: "https://api.dev.medable.com/example/v2/connections/552419f585b784bc204e73aa",
    method: "GET",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}).done(function(data) {
    // ...
});
MDObjectId* connectionId = [MDObjectId objectIdWithString:@"552419f585b784bc204e73aa"];

[[MDAPIClient sharedClient]
 connectionWithId:connectionId
 parameters:nil
 callback:^(MDConnection *connection, MDFault *fault)
 {
     if (fault)
     {
         // Fault handling
     }
 }];
APIClient.sharedInstance().getConnectionById(
        new ObjectId("552419f585b784bc204e73aa"),
        null,
        new ObjectFaultCallback<Connection>()
        {
            @Override
            public void call(Connection object, Fault fault)
            {
                if (null != fault)
                {
                    // Fault handling
                }
            }
        }
);
A binary file was returned

You couldn't be authenticated

{
    "_id": "552419f585b784bc204e73aa",
    "access": 2,
    "context": {
        "_id": "5519c01aae2fd2b02915c81f",
        "object": "c_example",
        "path": "/c_examples/5519c01aae2fd2b02915c81f"
    },
    "created": "2015-04-07T17:55:01.000Z",
    "creator": {
        "_id": "5516ee2634d8d93428169c0e",
        "object": "account",
        "path": "/accounts/5516ee2634d8d93428169c0e"
    },
    "expiresAt": "2015-04-14T17:55:01.032Z",
    "isArchived": false,
    "object": "connection",
    "state": 0,
    "target": {
        "account": {
            "_id": "552417e085b784bc204e737c",
            "object": "account",
            "path": "/accounts/552417e085b784bc204e737c"
        },
        "name": {
            "first": "Charles",
            "last": "Best"
        }
    },
    "token": "u0xJRTlDQD8moTuUqeQiCAaFzU1WPdtq"
}

Path Params

your_org_name
string
required
connection_id
string
required
 
Suggest Edits

Read (Token)

 

Header Auth

 Authentication is required for this endpoint.
gethttps://api.dev.medable.com/your_org_name/v2/connections/token
$.ajax({
    url: "https://api.dev.medable.com/example/v2/connections/u0xJRTlDQD8moTuUqeQiCAaFzU1WPdtq?expand[]=context",
    method: "GET",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}).done(function(data) {
    // ...
});
MDAPIParameters* parameters = [MDAPIParameterFactory parametersWithExpandPaths:@[ kContextKey ]];

[[MDAPIClient sharedClient]
 connectionWithToken:@"u0xJRTlDQD8moTuUqeQiCAaFzU1WPdtq"
 parameters:parameters
 callback:^(MDConnection *connection, MDFault *fault)
 {
     if (fault)
     {
         // Fault handling
     }
 }];
APIParameters parameters = APIParameterFactory.parametersWithExpandPaths(null, Constants.kContext);

APIClient.sharedInstance().getConnectionByToken(
        "u0xJRTlDQD8moTuUqeQiCAaFzU1WPdtq",
        parameters,
        new ObjectFaultCallback<Connection>()
        {
            @Override
            public void call(Connection object, Fault fault)
            {
                if (null != fault)
                {
                    // Fault handling
                }
            }
        }
);
A binary file was returned

You couldn't be authenticated

{
    "_id": "552419f585b784bc204e73aa",
    "access": 2,
    "context": {
        "_id": "5519c01aae2fd2b02915c81f",
        "access": 2,
        "creator": {
            "_id": "5516ee2634d8d93428169c0e",
            "object": "account",
            "path": "/accounts/5516ee2634d8d93428169c0e"
        },
        "favorite": false,
        "object": "c_example",
        "owner": {
            "_id": "5516ee2634d8d93428169c0e",
            "object": "account",
            "path": "/accounts/5516ee2634d8d93428169c0e"
        },
        "shared": true
    },
    "created": "2015-04-07T17:55:01.000Z",
    "creator": {
        "_id": "5516ee2634d8d93428169c0e",
        "object": "account",
        "path": "/accounts/5516ee2634d8d93428169c0e"
    },
    "expiresAt": "2015-04-14T17:55:01.032Z",
    "isArchived": false,
    "object": "connection",
    "state": 0,
    "target": {
        "account": {
            "_id": "552417e085b784bc204e737c",
            "object": "account",
            "path": "/accounts/552417e085b784bc204e737c"
        },
        "name": {
            "first": "Charles",
            "last": "Best"
        }
    },
    "token": "u0xJRTlDQD8moTuUqeQiCAaFzU1WPdtq"
}

Path Params

your_org_name
string
required
token
string
required
 

Header Auth

 Authentication is required for this endpoint.
posthttps://api.dev.medable.com/your_org_name/v2/object_name/object_id/connections
$.ajax({
    url: "https://api.dev.medable.com/example/v2/c_examples/5519c01aae2fd2b02915c81f/connections",
    method: "POST",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    },
    data: {
    "targets": [
        {
            "object": "account",
            "email": "fred.banting@example.org",
            "access": 4
        }
    ]
}
}).done(function(data) {
    // ...
});
MDObjectId* objectId = [MDObjectId objectIdWithString:@"5519c01aae2fd2b02915c81f"];

NSArray* targets = @[
                     @{
                         kObjectKey: kAccountContext,
                         kEmailKey: @"fred.banting@example.org",
                         kAccessKey: @(MDACLLevelRead)
                         }];

[[MDAPIClient sharedClient]
 createConnectionWithContext:@"c_examples"
 objectId:objectId
 targets:targets
 callback:^(MDFault *fault)
 {
     if (fault)
     {
         // Fault handling
     }
 }];
ConnectTarget accountTarget = ConnectTarget.createTarget(
        "fred.banting@example.org",
        ACLLevel.Read
);

Targets targets = Targets.createTargets(teamTarget, accountTarget);

APIClient.sharedInstance().createConnection(
        "c_examples",
        new ObjectId("5519c01aae2fd2b02915c81f"),
        targets,
        new FaultCallback()
        {
            @Override
            public void call(Fault fault)
            {
                if (null != fault)
                {
                    // Fault handling
                }
            }
        }
);
A binary file was returned

You couldn't be authenticated

{
  "hasMore": false,
  "object": "list",
  "data": [
    {
      "_id": "5524165d65a7158820f4c022",
      "access": 4,
      "context": {
        "_id": "5519c01aae2fd2b02915c81f",
        "object": "c_example",
        "path": "/c_examples/5519c01aae2fd2b02915c81f"
      },
      "created": "2015-04-07T17:39:41.000Z",
      "creator": {
        "_id": "5516ee2634d8d93428169c0e",
        "object": "account",
        "path": "/accounts/5516ee2634d8d93428169c0e"
      },
      "expiresAt": "2015-04-14T17:55:01.029Z",
      "object": "connection",
      "state": 0,
      "target": {
        "email": "fred.banting@example.org",
        "name": {
          "first": "",
          "last": ""
        }
      }
    }
  ]
}

Path Params

your_org_name
string
required
object_name
string
required
object_id
string
required

Body Params

targets
array of objects

An array of connection targets. The caller must have Connected access any team targets. For teams, a roles array will limit the connections to those members having the specified role(s).

_id
email
object
access
roles
 
Suggest Edits

Apply Connection

Accepting a connecting request

 

Header Auth

 Authentication is required for this endpoint.
posthttps://api.dev.medable.com/your_org_name/v2/connections/token
$.ajax({
    url: "https://api.dev.medable.com/example/v2/connections/GGrc5KoMMpMsEbDxh2iEsn1dcRmxnNY8",
    method: "POST",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}).done(function(data) {
    // ...
});
[[MDAPIClient sharedClient]
 acceptConnectionWithToken:@"GGrc5KoMMpMsEbDxh2iEsn1dcRmxnNY8"
 callback:^(MDFault *fault)
 {
     if (fault)
     {
         // Fault handling
     }
 }];
APIClient.sharedInstance().clearNotification(
        new ObjectId("55238af0b9b285167a2414c8"),
        new FaultCallback()
        {
            @Override
            public void call(Fault fault)
            {
                if (null != fault)
                {
                    // Fault handling
                }
            }
        }
);
A binary file was returned

You couldn't be authenticated

{
    "_id": "552427adccbc32041380264f",
    "access": 4,
    "context": {
        "_id": "5519c01aae2fd2b02915c81f",
        "object": "c_example",
        "path": "/c_examples/5519c01aae2fd2b02915c81f"
    },
    "created": "2015-04-07T18:53:33.000Z",
    "creator": {
        "_id": "5516ee2634d8d93428169c0e",
        "object": "account",
        "path": "/accounts/5516ee2634d8d93428169c0e"
    },
    "isArchived": false,
    "object": "connection",
    "state": 1,
    "target": {
        "account": {
            "_id": "552417e085b784bc204e737c",
            "object": "account",
            "path": "/accounts/552417e085b784bc204e737c"
        },
        "email": "charles+best@example.org",
        "name": {
            "first": "Charles",
            "last": "Best"
        }
    }
}

Path Params

your_org_name
string
required
token
string
required
 

Header Auth

 Authentication is required for this endpoint.
deletehttps://api.dev.medable.com/your_org_name/v2/connections/connection_id
$.ajax({
    url: "https://api.dev.medable.com/example/v2/connections/5524191c85b784bc204e739f",
    method: "DELETE",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}).done(function(data) {
    // ...
});
MDObjectId* connectionId = [MDObjectId objectIdWithString:@"5524191c85b784bc204e739f"];

[[MDAPIClient sharedClient]
 removeConnectionWithId:connectionId
 callback:^(MDFault *fault)
 {
     if (fault)
     {
         // Fault handling
     }
 }];
APIClient.sharedInstance().removeConnection(
        new ObjectId("5524191c85b784bc204e739f"),
        new FaultCallback()
        {
            @Override
            public void call(Fault fault)
            {
                if (null != fault)
                {
                    // Fault handling
                }
            }
        }
);
A binary file was returned

You couldn't be authenticated

{
    "object": "result",
    "data": true
}

Path Params

your_org_name
string
required
connection_id
string
required
 
Suggest Edits

Reject Connection

 

Header Auth

 Authentication is required for this endpoint.
deletehttps://api.dev.medable.com/your_org_name/v2/connections/token
$.ajax({
    url: "https://api.dev.medable.com/example/v2/connections/u0xJRTlDQD8moTuUqeQiCAaFzU1WPdtq",
    method: "DELETE",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}).done(function(data) {
    // ...
});
[[MDAPIClient sharedClient]
 rejectConnectionWithToken:@"u0xJRTlDQD8moTuUqeQiCAaFzU1WPdtq"
 callback:^(MDFault *fault)
 {
     if (fault)
     {
         // Fault handling
     }
 }];
APIClient.sharedInstance().rejectConnection(
        "u0xJRTlDQD8moTuUqeQiCAaFzU1WPdtq",
        new FaultCallback()
        {
            @Override
            public void call(Fault fault)
            {
                if (null != fault)
                {
                    // Fault handling
                }
            }
        }
);
A binary file was returned

You couldn't be authenticated

{
    "object": "result",
    "data": true
}

Path Params

your_org_name
string
required
token
string
required
 
Suggest Edits

Notification Object

 

Notification objects are either automatically created as a result of connection invitations or manually created via the Custom Notifications section on the admin portal.

Through the administration interface at https://app.dev.medable.com/{your_org_name}/settings/notifications, notifications can be enabled, disabled, or based on org members’ preferences.

In conjuction with the scripting api, custom notifications can be configured for multiple endpoints and sent via script (e.g. require("notifications").send("c_my_notif"); ).

An Organization can setup an app for Apple Push Notification Service (APNs) and Google Cloud Messaging (GCM), and users can set preferences for how to receive notifications, through APNs, via email or through SMS for custom notifications.

Notifications are automatically cleared for connection invitations when they are retrieved using the API. Otherwise, clients should manually clear them using the notifications API.

_id
ObjectId

The notification identifier.

context
Reference

The context for which the notification was created.

created
Date

The date the notification was created. Notifications that are not acknowledged expire after 30 days.

meta
Any

An object containing notification metadata. For post updates, for example, it contains the postId and postType. For comments, it also contains the commentId.

object
String

The object name (notification).

type
ObjectId

The notifcation type (Post Update: 1, Invitation: 2, Transfer Request: 3, Comment Update: 4)

{
    "_id": "55238637b9b285167a241439",
    "object": "notification",
    "type": 1,
    "context": {
        "_id": "5519c01aae2fd2b02915c81f",
        "object": "c_example",
        "path": "/c_examples/5519c01aae2fd2b02915c81f"
    },
    "meta": {
        "postId": "55238637a033479c18311c6e",
        "type": "c_post"
    }
}

Header Auth

 Authentication is required for this endpoint.
gethttps://api.dev.medable.com/your_org_name/v2/notifications
$.ajax({
    url: "https://api.dev.medable.com/example/v2/notifications",
    method: "GET",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}).done(function(data) {
    // ...
});
[[MDAPIClient sharedClient]
 listNotificationsWithParameters:nil
 callback:^(NSArray *notifications, NSNumber *hasMore, MDFault *fault)
 {
     if (fault)
     {
         // Fault handling
     }
 }];
APIClient.sharedInstance().listNotifications(
  null,
  new ObjectsListCallback<GCMNotification>()
  {
    @Override
    public void call(List<GCMNotification> results, boolean hasMore, Fault fault)
    {
      if (null != fault)
      {
        // Fault handling
      }
    }
  }
);
A binary file was returned

You couldn't be authenticated

{
  "data": [
    {
      "_id": "55238637b9b285167a241439",
      "context": {
        "_id": "5519c01aae2fd2b02915c81f",
        "object": "c_example",
        "path": "/c_examples/5519c01aae2fd2b02915c81f"
      },
      "meta": {
        "postId": "55238637a033479c18311c6e",
        "type": "c_post"
      },
      "object": "notification",
      "type": "4e66204665656473506f7374"
    },
    {
      "_id": "5523860eb9b285167a241431",
      "context": {
        "_id": "5519c01aae2fd2b02915c81f",
        "object": "c_example",
        "path": "/c_examples/5519c01aae2fd2b02915c81f"
      },
      "meta": {
        "commentId": "5523860ea033479c18311c65",
        "postId": "55238235bb12a3841950d37e",
        "type": "c_post"
      },
      "object": "notification",
      "type": "4e66204665656473436d6e74"
    }
  ],
  "hasMore": false,
  "object": "list"
}

Path Params

your_org_name
string
required
 

Header Auth

 Authentication is required for this endpoint.
gethttps://api.dev.medable.com/your_org_name/v2/notifications/notification_id
$.ajax({
    url: "https://api.dev.medable.com/example/v2/notifications/55238637b9b285167a241439",
    method: "GET",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}).done(function(data) {
    // ...
});
[[MDAPIClient sharedClient]
 listNotificationsWithParameters:nil
 callback:^(NSArray *notifications, NSNumber *hasMore, MDFault *fault)
 {
     if (fault)
     {
         // Fault handling
     }
 }];
APIClient.sharedInstance().listNotifications(
  null,
  new ObjectsListCallback<GCMNotification>()
  {
    @Override
    public void call(List<GCMNotification> results, boolean hasMore, Fault fault)
    {
      if (null != fault)
      {
        // Fault handling
      }
    }
  }
);
A binary file was returned

You couldn't be authenticated

{
  "_id": "55238637b9b285167a241439",
  "context": {
    "_id": "5519c01aae2fd2b02915c81f",
    "object": "c_example",
    "path": "/c_examples/5519c01aae2fd2b02915c81f"
  },
  "meta": {
    "postId": "55238637a033479c18311c6e",
    "type": "c_post"
  },
  "object": "notification",
  "type": "4e66204665656473506f7374"
}

Path Params

your_org_name
string
required
notification_id
string
required
 
Suggest Edits

Clear (One)

 

Header Auth

 Authentication is required for this endpoint.
deletehttps://api.dev.medable.com/your_org_name/v2/notifications/notification_id
$.ajax({
    url: "https://api.dev.medable.com/example/v2/notifications/55238af0b9b285167a2414c8",
    method: "DELETE",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}).done(function(data) {
    // ...
});
[[MDAPIClient sharedClient]
 clearNotificationWithId:[MDObjectId objectIdWithString:@"55238af0b9b285167a2414c8"]
 callback:^(MDFault *fault)
 {
     if (fault)
     {
         // Fault handling
     }
 }];
APIClient.sharedInstance().clearNotification(
  new ObjectId("55238af0b9b285167a2414c8"),
  new FaultCallback()
  {
    @Override
    public void call(Fault fault)
    {
      if (null != fault)
      {
        // Fault handling
      }
    }
  }
);
A binary file was returned

You couldn't be authenticated

{
    "object": "result",
    "data": 1
}

Path Params

your_org_name
string
required
notification_id
string
required
 
Suggest Edits

Clear (Many)

 

Header Auth

 Authentication is required for this endpoint.
deletehttps://api.dev.medable.com/your_org_name/v2/notifications/object_name/object_id
$.ajax({
    url: "https://api.dev.medable.com/example/v2/notifications/c_examples/5519c01aae2fd2b02915c81f?type=4e6620436e6e637443727464",
    method: "DELETE",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}).done(function(data) {
    // ...
});
[[MDAPIClient sharedClient]
 clearNotificationsWithType:MDNotificationTypePostUpdate
 context:@"c_examples"
 objectId:[MDObjectId objectIdWithString:@"5519c01aae2fd2b02915c81f"]
 callback:^(MDFault *fault)
 {
     if (fault)
     {
         // Fault handling
     }
 }];
APIClient.sharedInstance().clearNotifications(
  GCMNotificationType.PostUpdate,
  "c_examples",
  new ObjectId("5519c01aae2fd2b02915c81f"),
  new FaultCallback()
  {
    @Override
    public void call(Fault fault)
    {
      if (null != fault)
      {
        // Fault handling
      }
    }
  }
);
A binary file was returned

You couldn't be authenticated

{
    "object": "result",
    "data": 1
}

Path Params

your_org_name
string
required
object_name
string
required
object_id
string
required
 
Suggest Edits

Stat Object

 
Name
Description

_id
ObjectId

The stat object identifier

starting
Date

The starting time for this stat time frame.

ending
Date

The ending time for this stat time frame.

org
ObjectId

The org that this stat lives in

object
String

The object name (stat)

code
Number

The number that determines what kind of event this stat instance is representing.
Request: 0
File Storage: 1
Document Storage: 2
Logins: 3
Accounts: 4
Scripts: 5
Notifications: 6

count
Number

How many times this stat event has occurred in the time frame.

size
Number

The size of the file or document stored. Used for code 2 stats.

total
Number

Similar to count but used for different stat codes.

s_source
String

Storage source name (e.g. account)

s_object
String

Storage object name (e.g. account)

s_type
String

Storage type name

s_property
ObjectId

Storage property name

today
Number

active
Number

location
Number

1 if data stored to Medable
2 if stored to Amazon s3

method
Number

GET: 0
POST: 1
PUT: 2
DELETE: 3
HEAD: 4
OPTIONS: 5
PATCH: 6

api
String

The api endpoint that was called

client
ObjectId

The object id of the app that's issuing the request, if defined. (relevant only for request stats)

ms
Number

The total number of milliseconds it took to complete this task

in
Number

The total number of bytes in

out
Number

The total number of bytes out

errs
Number

The number of errors

scriptId
ObjectId

The script identifier

scriptType
String

Script type (like "route", "trigger", etc)

callouts
Number

Total number of HTTP callouts used in the script

calloutsMs
Number

Total milliseconds of HTTP callouts in the script

ops
Number

Number of operations used in the script

notifType
ObjectId

The notification object identifier. A notification might be a standard or custom one defined in the Notifications tab of the admin interface.

notifEndpoint
ObjectId

The notification endpoint identifier. Each notification might have an email, sms, or push endpoint.

{
  "_id": "575f58bfa588cb8881e49833",
  "api": "",
  "client": null,
  "code": 0,
  "count": 1,
  "ending": "2016-06-14T01:59:59.999Z",
  "in": 0,
  "location": 1,
  "method": 0,
  "ms": 22,
  "object": "stat",
  "org": "575f58271d0c03a53ccc3840",
  "out": 2871,
  "starting": "2016-06-14T01:00:00.000Z"
}

Header Auth

 Authentication is required for this endpoint.
gethttps://api.dev.medable.com/your_org_name/v2/stats
$.ajax({
    url: "https://api.dev.medable.com/example/v2/stats",
    method: "GET",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}).done(function(data) {
    // ...
});
A binary file was returned

You couldn't be authenticated

{
    "data": [
        {
            "_id": "5810f6c3773c2ecc9439e34e",
            "api": "sys",
            "client": null,
            "code": 0,
            "count": 2,
            "ending": "2016-10-26T18:59:59.999Z",
            "in": 2302,
            "location": 1,
            "method": 1,
            "ms": 266,
            "object": "stat",
            "org": "5810f10e6d66738355843d7d",
            "out": 1514,
            "starting": "2016-10-26T18:00:00.000Z"
        },
        {
            "_id": "5810f6c3773c2ecc9439e350",
            "api": "",
            "client": null,
            "code": 0,
            "count": 5,
            "ending": "2016-10-26T18:59:59.999Z",
            "in": 4619,
            "location": 1,
            "method": 0,
            "ms": 222,
            "object": "stat",
            "org": "5810f10e6d66738355843d7d",
            "out": 15400,
            "starting": "2016-10-26T18:00:00.000Z"
        },
        {
            "_id": "5810f6c4773c2ecc9439e352",
            "api": "orgs",
            "client": null,
            "code": 0,
            "count": 25,
            "ending": "2016-10-26T18:59:59.999Z",
            "in": 22794,
            "location": 1,
            "method": 0,
            "ms": 1532,
            "object": "stat",
            "org": "5810f10e6d66738355843d7d",
            "out": 16325,
            "starting": "2016-10-26T18:00:00.000Z"
        },
        {
            "_id": "5810f6c4773c2ecc9439e354",
            "api": "accounts",
            "client": null,
            "code": 0,
            "count": 6,
            "ending": "2016-10-26T18:59:59.999Z",
            "in": 5419,
            "location": 1,
            "method": 0,
            "ms": 410,
            "object": "stat",
            "org": "5810f10e6d66738355843d7d",
            "out": 3786,
            "starting": "2016-10-26T18:00:00.000Z"
        }
      ],
    "hasMore": true,
    "object": "list"
}

Path Params

your_org_name
string
required
 
Suggest Edits

Log Object

 

_id
ObjectId

Log object instance identifier

org
ObjectId

Org identifier

req
ObjectId

Request identifier

pid
ObjectId

Principal Identifier - The principal is the authenticated entity that issued the request

oid
ObjectId

Original Principal Identifier - The original principal is the authenticated entity that issued the first request. The "run as" argument of scripts could make the pid different from oid.

beg
Date

Start date of this log instance

end
Date

End date of this log instance

exp
Date

The expiration date of this log instance. This is set to 30 days from the beg date. To have logs persist longer, please contact support.

sts
Number

HTTP status code (like 2xx, 3xx, 4xx)

src
Number

logger: 0
api: 1
script: 2
request: 3
audit: 4
deployment: 5
export: 6

lvl
Number

error: 0
warn: 1
info: 2
debug: 3
trace: 4

trc
Document

Stack trace (file, line number, function)

err
Document

Error details (error name, message, reason, faults, etc)

in
Number

Total bytes in

out
Number

Total bytes out

sid
ObjectId

Script identifier

stp
String

Script type (like "route", "trigger", etc)

ops
Number

Number of operations used in the script

ctt
Number

Total number of HTTP callouts used in the script

cms
Number

Total milliseconds of HTTP callouts in the script

adr
Number

Source IP address

mtd
Number

Request method
GET: 0
POST: 1
PUT: 2
DELETE: 3
HEAD: 4
OPTIONS: 5
PATCH: 6

url
String

Request URL path

que
Any

Request query params

rte
String

API route

aid
ObjectId

App ID

cid
ObjectId

App client ID

ses
String

Session ID

lid
ObjectId

Location ID

dat
Any

Any data passed in via the Logger

op
Number

Operation Code
set: 1
remove: 2 // remove a property value
push: 3
pull: 4
delete: 5 // delete an instance
auth: 6 // authentication event
transfer: 7 // ownership transfer
device: 8 // new device registered for account
access: 9 // instance access granted/removed

ctx
ObjectId

Context ID

obj
String

Object Name

ads
Number

Audit Source
request: 1
script: 2
system: 3

acs
Number

Natural Access

grt
Number

Granted Access

pts
String

Updated Paths

pis
ObjectId

Updated Property Identifiers

dpl
ObjectId

Deployment Identifier

{
  "_id": "59433e6a8cb4760100c7216e",
  "adr": 1187315762,
  "aid": "5810f6e4cc761537539d3e2c",
  "beg": "2017-06-16T02:11:54.702Z",
  "cid": "5810f6e4cc761537539d3e2d",
  "end": "2017-06-16T02:11:55.199Z",
  "err": {
    "faults": []
  },
  "in": 417,
  "lvl": 2,
  "mtd": 0,
  "out": 525,
  "pis": [],
  "pts": [],
  "que": {
    "c_public_user": "593b2a2f9a8ca001000f0435",
    "c_study": "58faa94410cc4501001fe779"
  },
  "req": "59433e6a81ae9d0100e9fca7",
  "rte": "/routes/get_public_group*",
  "src": 3,
  "sts": 200,
  "trc": [],
  "url": "/routes/get_public_group"
}

Header Auth

 Authentication is required for this endpoint.
gethttps://api.dev.medable.com/your_org_name/v2/logs
$.ajax({
    url: "https://api.dev.medable.com/example/v2/logs",
    method: "GET",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}).done(function(data) {
    // ...
});
A binary file was returned

You couldn't be authenticated

{
    "data": [
        {
            "_id": "59433e6a7a90230100f4815f",
            "adr": 1187315762,
            "aid": "5810f6e4cc761537539d3e2c",
            "beg": "2017-06-16T02:11:54.248Z",
            "cid": "5810f6e4cc761537539d3e2d",
            "end": "2017-06-16T02:11:54.265Z",
            "err": {
                "faults": []
            },
            "in": 321,
            "lvl": 2,
            "mtd": 0,
            "out": 0,
            "pis": [],
            "pts": [],
            "req": "59433e6ab3eb3f0100ded3bd",
            "rte": "/",
            "src": 3,
            "sts": 200,
            "trc": [],
            "url": "/"
        },
        {
            "_id": "59433e6a8cb4760100c7216e",
            "adr": 1187315762,
            "aid": "5810f6e4cc761537539d3e2c",
            "beg": "2017-06-16T02:11:54.702Z",
            "cid": "5810f6e4cc761537539d3e2d",
            "end": "2017-06-16T02:11:55.199Z",
            "err": {
                "faults": []
            },
            "in": 417,
            "lvl": 2,
            "mtd": 0,
            "out": 525,
            "pis": [],
            "pts": [],
            "que": {
                "c_public_user": "593b2a2f9a8ca001000f0435",
                "c_study": "58faa94410cc4501001fe779"
            },
            "req": "59433e6a81ae9d0100e9fca7",
            "rte": "/routes/get_public_group*",
            "src": 3,
            "sts": 200,
            "trc": [],
            "url": "/routes/get_public_group"
        },
        {
            "_id": "59433e6a8cb4760100c72170",
            "beg": "2017-06-16T02:11:54.904Z",
            "cms": 0,
            "ctt": 0,
            "dat": [
                19
            ],
            "end": "2017-06-16T02:11:54.904Z",
            "err": {
                "faults": []
            },
            "in": 0,
            "lvl": 2,
            "oid": "000000000000000000000001",
            "ops": 362,
            "out": 0,
            "pid": "58e2745649b3c401002b53d7",
            "pis": [],
            "pts": [],
            "req": "59433e6a81ae9d0100e9fca7",
            "sid": "59139ef6b0cc5f01004714d8",
            "src": 0,
            "stp": "route",
            "sts": 200,
            "trc": []
        }
      ],
    "hasMore": true,
    "object": "list"
}

Path Params

your_org_name
string
required
 
Suggest Edits

Export Object

 

You can create data exports through the admin UI or directly through the API. Creating exports through the API is helpful when needing to automate an export process.

Export object instances define export jobs to run including details such as type of export, query and aggregation criteria, export paths to include, and more. Each export instance represents one specific export job. Export jobs are queued in the background and each org can run one job at a time. Although you can create as many export jobs as you'd like, they will run sequentially in the order they were created.

Exported data is archived in zip format and stored securely in an encrypted file store within Cortex. When the export job is complete, a secure download link will be provided in the export's dataFile property. This link can only be accessed by an authenticated user with administrator privileges. Exports are available for download for seven days, after which the export and archive are deleted.

Note

Export archive sizes count against file storage limits in your org.

Export Object Properties

Name
Type
Description

label

String

The label for your export. This appears in the export jobs UI

description

String

The description of your export. If present, this appears in the export jobs UI

state

String

The current state of the export job. Can be pending, running, ready, error

exportFiles

Boolean

When selected, if the export contains files, they will be included along-side the exported data. Note, this can cause exports to take a long time to complete if there are many large files.

zipFiles

Boolean

Applies with exporting files. If true, files are archived together in a zip archive within the exported archive.

format

MIME-type

The format of the exported data. Valid types are:

  • application/x-ndjson: New-line delimited JSON
  • application/json: JSON format
  • text/csv: CSV format

objects

String

The name of the Cortex object being exported.

paths

String Array

Optional array of property names to include in the export. When no paths are provided, all non-optional paths are included.

include

String Array

An array of optional property names to be included in the export.

expand

String Array

An array of reference property names to be expanded in the export.

where

String

Optional query argument to filter the export. See the Where query argument for more details.

afterScript

String

A stringified custom script that will execute after export job completion. This is helpful for logging the completion of exports or sending notifications, etc.

Header Auth

 Authentication is required for this endpoint.
gethttps://api.dev.medable.com/your_org_name/v2/exports
$.ajax({
    url: "https://api.dev.medable.com/example/v2/exports",
    method: "GET",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}).done(function(data) {
    // ...
});
A binary file was returned

You couldn't be authenticated

{
    "data": [
        {
            "_id": "595d68f40e74ad01008c52df",
            "access": 7,
            "created": "2017-07-05T22:32:20.753Z",
            "creator": {
                "_id": "5532e499540b0183799b4ee5",
                "object": "account",
                "path": "/accounts/5532e499540b0183799b4ee5"
            },
            "dataFile": {
                "ETag": "6d3ccfae24f5128b62525f33999525e0",
                "creator": "5532e499540b0183799b4ee5",
                "filename": "export-2017-07-05T22:32:21.228Z.json",
                "location": 4,
                "mime": "application/zip",
                "name": "content",
                "path": "/exports/595d68f40e74ad01008c52df/dataFile/content",
                "size": 353,
                "state": 2
            },
            "expiresAt": "2017-07-12T22:32:20.771Z",
            "format": "application/json",
            "label": "My Export",
            "object": "export",
            "objects": "c_goals",
            "owner": {
                "_id": "5532e499540b0183799b4ee5",
                "object": "account",
                "path": "/accounts/5532e499540b0183799b4ee5"
            },
            "state": "ready",
            "stats": {
                "docs": {
                    "count": 2
                },
                "files": {
                    "count": 0,
                    "size": 0
                }
            }
        },
        {
            "_id": "595d6b5a0e74ad01008c537a",
            "access": 7,
            "created": "2017-07-05T22:42:34.614Z",
            "creator": {
                "_id": "5532e499540b0183799b4ee5",
                "object": "account",
                "path": "/accounts/5532e499540b0183799b4ee5"
            },
            "dataFile": {
                "ETag": "7afba9849047dc37047c609b48c1020a",
                "creator": "5532e499540b0183799b4ee5",
                "filename": "export-2017-07-05T22:42:35.030Z.csv",
                "location": 4,
                "mime": "application/zip",
                "name": "content",
                "path": "/exports/595d6b5a0e74ad01008c537a/dataFile/content",
                "size": 910,
                "state": 2
            },
            "expiresAt": "2017-07-12T22:42:34.624Z",
            "format": "text/csv",
            "label": "My Export 2",
            "object": "export",
            "objects": "c_patients",
            "owner": {
                "_id": "5532e499540b0183799b4ee5",
                "object": "account",
                "path": "/accounts/5532e499540b0183799b4ee5"
            },
            "paths": [
                "_id",
                "created",
                "c_birthdate",
                "c_gender",
                "c_name"
            ],
            "state": "ready",
            "stats": {
                "docs": {
                    "count": 26
                },
                "files": {
                    "count": 0,
                    "size": 0
                }
            }
        }
    ],
    "hasMore": false,
    "object": "list"
}

Path Params

your_org_name
string
required
 

Header Auth

 Authentication is required for this endpoint.
gethttps://api.dev.medable.com/your_org_name/v2/exports/export_id
$.ajax({
    url: "https://api.dev.medable.com/example/v2/exports/595d68f40e74ad01008c52df",
    method: "GET",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}).done(function(data) {
    // ...
});
A binary file was returned

You couldn't be authenticated

{
  "_id": "595d68f40e74ad01008c52df",
  "access": 7,
  "created": "2017-07-05T22:32:20.753Z",
  "creator": {
    "_id": "5532e499540b0183799b4ee5",
    "object": "account",
    "path": "/accounts/5532e499540b0183799b4ee5"
  },
  "dataFile": {
    "ETag": "6d3ccfae24f5128b62525f33999525e0",
    "creator": "5532e499540b0183799b4ee5",
    "filename": "export-2017-07-05T22:32:21.228Z.json",
    "location": 4,
    "mime": "application/zip",
    "name": "content",
    "path": "/exports/595d68f40e74ad01008c52df/dataFile/content",
    "size": 353,
    "state": 2
  },
  "expiresAt": "2017-07-12T22:32:20.771Z",
  "format": "application/json",
  "label": "My Export",
  "object": "export",
  "objects": "c_goals",
  "owner": {
    "_id": "5532e499540b0183799b4ee5",
    "object": "account",
    "path": "/accounts/5532e499540b0183799b4ee5"
  },
  "state": "ready",
  "stats": {
    "docs": {
      "count": 2
    },
    "files": {
      "count": 0,
      "size": 0
    }
  }
}

Path Params

your_org_name
string
required
export_id
string
required
 

Header Auth

 Authentication is required for this endpoint.
posthttps://api.dev.medable.com/your_org_name/v2/exports
$.ajax({
    url: "https://api.dev.medable.com/example/v2/exports",
    method: "POST",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    },
    data: {
      {
        "label": "My Export",
        "format": "text/csv",
        "objects": "c_patients",
        "paths": ["_id", "created", "c_birthdate", "c_gender", "c_name"],
        "afterScript": "import logger from 'logger';\nlogger.info(script.arguments.err || script.arguments.export);\n"
      }
		}
}).done(function(data) {
    // ...
});
A binary file was returned

You couldn't be authenticated

{
  "_id": "595d6b5a0e74ad01008c537a",
  "object": "export",
  "created": "2017-07-05T22:42:34.614Z",
  "creator": {
    "_id": "5532e499540b0183799b4ee5",
    "object": "account",
    "path": "/accounts/5532e499540b0183799b4ee5"
  },
  "owner": {
    "_id": "5532e499540b0183799b4ee5",
    "object": "account",
    "path": "/accounts/5532e499540b0183799b4ee5"
  },
  "access": 7,
  "label": "test 3",
  "state": "pending",
  "exportFiles": false,
  "zipFiles": false,
  "format": "text/csv",
  "objects": "c_patients",
  "paths": [
    "_id", "created", "c_birthdate", "c_gender", "c_name"
  ],
  "afterScript": "import logger from 'logger';\nlogger.info(script.arguments.err || script.arguments.export);\n",
  "stats": {
    "docs": {
      "count": 0
    },
    "files": {
      "count": 0,
      "size": 0
    }
  },
  "expiresAt": "2017-07-12T22:42:34.624Z"
}

Path Params

your_org_name
string
required

Body Params

label
string
objects
string
format
string
exportFiles
boolean
zipFiles
boolean
 

Header Auth

 Authentication is required for this endpoint.
deletehttps://api.dev.medable.com/your_org_name/v2/exports/export_id
$.ajax({
    url: "https://api.dev.medable.com/example/v2/connections/595d6b5a0e74ad01008c537a",
    method: "DELETE",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}).done(function(data) {
    // ...
});
A binary file was returned

You couldn't be authenticated

{
    "object": "result",
    "data": true
}

Path Params

your_org_name
string
required
export_id
string
required
 
Suggest Edits

Object Definition

 

Introduction

You can extend the API by creating new custom objects and extending the standard objects with custom properties, You can do this via the API if you have the Administrator or Developer roles, or via the admin UI. For details on how to create and extend objects using the admin UI, see Data Model Setup.

At every level, custom objects and properties are prefixed with c_ to differentiate them from standard properties that may be placed alongside in a document. For example, retrieving a custom property from a custom object might look like GET /c_records/551ebec0f6b25fd828742de1/c_info

Although a standard object's standard properties cannot be modified, custom properties can be added to extensible standard object classes.

Also some of the standard object’s properties can either be overridden or extended, including the createAcl, defaultAcl and shareAcl.

Object Definition

_id
ObjectId

The object definition identifier.

label
String

The object label.

name
String

The object name.

pluralName
String

Based on the name, this is the name used in API routes. For example, to retrieve a list of c_thing objects, use GET /c_things

description
String

The object description.

defaultAcl
Document

All contexts objects of this type will have this ACL merged with their instance ACL.

createAcl
Document

These ACL targets are able to create context objects of this type.

shareAcl
Document

These ACL targets are able to share context objects of this type. The entries defined which access levels and roles can be assigned by which targets.

shareChain
Number

A caller can create a connection granting any level of access in the share chain, as long as it is less than his own.

allowTransfers
Boolean

Allow ownership transfer for this context\'s objects.

allowConnections
Boolean

Set to enable/disable sharing of contexts for this object.

connectionOptions
Document

Options around connection requests, such as whether to auto-accept and send-notification.

properties
Document Array

All of the properties defined in this object class.

object
String

The context’s object name.

objectTypes
Array

The object's types. For more info, see Object Types.

hasETag
Boolean

If true, an ETag property is made available and is (re)generated on an instance whenever it is updated.

Example Object Definition

{
  "_id": "576870f71d0c03a53cd665cd",
  "access": 7,
  "allowConnections": true,
  "allowTransfers": true,
  "connectionOptions": {
    "requireAccept": true,
    "requiredAccess": 5,
    "sendNotifications": true
  },
  "createAcl": [
    {
      "_id": "576870f71d0c03a53cd665ce",
      "allow": 1,
      "target": "000000000000000000000003",
      "type": 1
    }
  ],
  "created": "2016-06-20T22:40:55.523Z",
  "creator": {
    "_id": "575f58281d0c03a53ccc3ac6",
    "object": "account",
    "path": "/accounts/575f58281d0c03a53ccc3ac6"
  },
  "defaultAcl": [
    {
      "_id": "57b1ebac14e8971b6add7c66",
      "allow": 7,
      "type": 4
    },
    {
      "_id": "57b1ebac14e8971b6add7c67",
      "allow": 4,
      "target": "578483dc46b010416571393d",
      "type": 3
    }
  ],
  "label": "Prescription",
  "lookup": "576870f71d0c03a53cd665cd",
  "name": "c_prescription",
  "object": "object",
  "objectTypes": [],
  "pluralName": "c_prescriptions",
  "properties": [
    {
      "_id": "576d71d01d0c03a53cde6e88",
      "acl": [],
      "auditable": false,
      "autoCreate": false,
      "cascadeDelete": false,
      "creatable": false,
      "expandable": true,
      "grant": 2,
      "indexed": true,
      "label": "Patient",
      "name": "c_patient",
      "optional": false,
      "pacl": [],
      "paths": [],
      "readAccess": 4,
      "readable": true,
      "referenceAccess": 0,
      "removable": false,
      "sourceObject": "account",
      "type": "Reference",
      "unique": false,
      "validators": [],
      "writable": true,
      "writeAccess": 6
    },
    {
      "_id": "576d72a41d0c03a53cde7144",
      "acl": [],
      "array": false,
      "auditable": false,
      "canPull": true,
      "canPush": true,
      "creatable": false,
      "indexed": true,
      "label": "Rx",
      "lowercase": false,
      "maxItems": 100,
      "maxShift": false,
      "minItems": 0,
      "name": "c_rx",
      "optional": false,
      "readAccess": 4,
      "readable": true,
      "removable": false,
      "trim": false,
      "type": "String",
      "unique": false,
      "uniqueValues": false,
      "uppercase": false,
      "validators": [
        {
          "_id": "57914b65356ff1a73d2db0cf",
          "definition": {
            "max": 10000000000,
            "min": 0
          },
          "name": "printableString"
        },
        {
          "_id": "57914b65356ff1a73d2db0d0",
          "name": "required"
        }
      ],
      "writable": true,
      "writeAccess": 6,
      "writeOnCreate": true
    }
  ],
  "shareChain": [
    5,
    4,
    2
  ],
  "updated": "2017-05-26T04:08:39.488Z",
  "updater": {
    "_id": "5771495a1d0c03a53ce83f1a",
    "object": "account",
    "path": "/accounts/5771495a1d0c03a53ce83f1a"
  }
}

Header Auth

 Authentication is required for this endpoint.
gethttps://api.dev.medable.com/your_org_name/v2/objects
$.ajax({
    url: "https://api.dev.medable.com/example/v2/objects",
    method: "GET",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}
}).done(function(data) {
    // ...
});
A binary file was returned

You couldn't be authenticated

{
  "data": [
    {
      "_id": "594da5c0cfc40501006d2d33",
      "access": 7,
      "allowConnections": true,
      "allowTransfers": true,
      "connectionOptions": {
        "requireAccept": true,
        "requiredAccess": 5,
        "sendNotifications": true
      },
      "createAcl": [
        {
          "_id": "594da5c011f67101005a2b12",
          "allow": 1,
          "target": "000000000000000000000003",
          "type": 1
        }
      ],
      "created": "2017-06-23T23:35:28.787Z",
      "creator": {
        "_id": "5771495a1d0c03a53ce83f1a",
        "object": "account",
        "path": "/accounts/5771495a1d0c03a53ce83f1a"
      },
      "defaultAcl": [
        {
          "_id": "594da5c011f67101005a2b11",
          "allow": 1,
          "target": "000000000000000000000003",
          "type": 1
        }
      ],
      "favorite": false,
      "feedDefinition": [],
      "label": "exam",
      "lookup": "594da5c0cfc40501006d2d33",
      "name": "c_exam",
      "object": "object",
      "objectTypes": [],
      "pluralName": "c_exams",
      "properties": [],
      "shareChain": []
    }
  ],
  "hasMore": false,
  "object": "list"
}

Path Params

your_org_name
string
required
 

Header Auth

 Authentication is required for this endpoint.
gethttps://api.dev.medable.com/your_org_name/v2/objects/object_id
$.ajax({
    url: "https://api.dev.medable.com/example/v2/objects/594da5c0cfc40501006d2d33",
    method: "GET",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}
}).done(function(data) {
    // ...
});
A binary file was returned

You couldn't be authenticated

{
  "_id": "594da5c0cfc40501006d2d33",
  "access": 7,
  "allowConnections": true,
  "allowTransfers": true,
  "connectionOptions": {
    "requireAccept": true,
    "requiredAccess": 5,
    "sendNotifications": true
  },
  "createAcl": [
    {
      "_id": "594da5c011f67101005a2b12",
      "allow": 1,
      "target": "000000000000000000000003",
      "type": 1
    }
  ],
  "created": "2017-06-23T23:35:28.787Z",
  "creator": {
    "_id": "5771495a1d0c03a53ce83f1a",
    "object": "account",
    "path": "/accounts/5771495a1d0c03a53ce83f1a"
  },
  "defaultAcl": [
    {
      "_id": "594da5c011f67101005a2b11",
      "allow": 1,
      "target": "000000000000000000000003",
      "type": 1
    }
  ],
  "favorite": false,
  "feedDefinition": [],
  "label": "exam",
  "lookup": "594da5c0cfc40501006d2d33",
  "name": "c_exam",
  "object": "object",
  "objectTypes": [],
  "pluralName": "c_exams",
  "properties": [],
  "shareChain": []
}

Path Params

your_org_name
string
required
object_id
string
required
 

Header Auth

 Authentication is required for this endpoint.
posthttps://api.dev.medable.com/your_org_name/v2/objects
$.ajax({
    url: "https://api.dev.medable.com/example/v2/objects",
    method: "POST",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    },
    data: {
    "label": "pulse",
    "name" : "pulse",
    "defaultAcl": [
        {
            "target": "000000000000000000000003",
            "type": 1
        }
    ],
    "createAcl": [
        {
            "target": "000000000000000000000003",
            "type": 1
        }
    ]
}
}).done(function(data) {
    // ...
});
A binary file was returned

You couldn't be authenticated

{
    "_id": "594da5c0cfc40501006d2d33",
    "access": 7,
    "allowConnections": true,
    "allowTransfers": true,
    "connectionOptions": {
        "requireAccept": true,
        "requiredAccess": 5,
        "sendNotifications": true
    },
    "createAcl": [
        {
            "_id": "594da5c011f67101005a2b12",
            "allow": 1,
            "target": "000000000000000000000003",
            "type": 1
        }
    ],
    "created": "2017-06-23T23:35:28.787Z",
    "creator": {
        "_id": "5771495a1d0c03a53ce83f1a",
        "object": "account",
        "path": "/accounts/5771495a1d0c03a53ce83f1a"
    },
    "defaultAcl": [
        {
            "_id": "594da5c011f67101005a2b11",
            "allow": 1,
            "target": "000000000000000000000003",
            "type": 1
        }
    ],
    "favorite": false,
    "feedDefinition": [],
    "label": "exam",
    "lookup": "594da5c0cfc40501006d2d33",
    "name": "c_exam",
    "object": "object",
    "objectTypes": [],
    "pluralName": "c_exams",
    "properties": [],
    "shareChain": []
}

Path Params

your_org_name
string
required

Body Params

label
string
required
name
string
required
description
string
defaultAcl
json
createAcl
json
shareChain
array of integers
allowConnections
boolean
connectionOptions
json
properties
array of objects
name
label
type
objectTypes
array of objects
JSON
 

Header Auth

 Authentication is required for this endpoint.
puthttps://api.dev.medable.com/your_org_name/v2/objects/object_id
$.ajax({
    url: "https://api.dev.medable.com/example/v2/objects/594da5c0cfc40501006d2d33",
    method: "PUT",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    },
    data: {
    "allowConnections": "false"
}
}).done(function(data) {
    // ...
});
A binary file was returned

You couldn't be authenticated

{
    "_id": "594da5c0cfc40501006d2d33",
    "access": 7,
    "allowConnections": false,
    "allowTransfers": true,
    "connectionOptions": {
        "requireAccept": true,
        "requiredAccess": 5,
        "sendNotifications": true
    },
    "createAcl": [
        {
            "_id": "594da5c011f67101005a2b12",
            "allow": 1,
            "target": "000000000000000000000003",
            "type": 1
        }
    ],
    "created": "2017-06-23T23:35:28.787Z",
    "creator": {
        "_id": "5771495a1d0c03a53ce83f1a",
        "object": "account",
        "path": "/accounts/5771495a1d0c03a53ce83f1a"
    },
    "defaultAcl": [
        {
            "_id": "594da5c011f67101005a2b11",
            "allow": 1,
            "target": "000000000000000000000003",
            "type": 1
        }
    ],
    "favorite": false,
    "feedDefinition": [],
    "label": "exam",
    "lookup": "594da5c0cfc40501006d2d33",
    "name": "c_exam",
    "object": "object",
    "objectTypes": [],
    "pluralName": "c_exams",
    "properties": [],
    "shareChain": [],
    "updated": "2017-06-23T23:58:36.944Z",
    "updater": {
        "_id": "5771495a1d0c03a53ce83f1a",
        "object": "account",
        "path": "/accounts/5771495a1d0c03a53ce83f1a"
    }
}

Path Params

your_org_name
string
required
object_id
string
required

Body Params

label
string
description
string
defaultAcl
json
createAcl
json
shareChain
array of integers
allowConnections
boolean
connectionOptions
json
properties
array of objects
name
label
type
objectTypes
array of objects
JSON
 

Header Auth

 Authentication is required for this endpoint.
deletehttps://api.dev.medable.com/your_org_name/v2/objects/object_class_id
$.ajax({
    url: "https://api.dev.medable.com/example/v2/objects/594da5c0cfc40501006d2d33",
    method: "DELETE",
    dataType : "json",
    xhrFields: {
        withCredentials: true
    },
    headers: {
        "Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"
    }
}).done(function(data) {
    // ...
});
A binary file was returned

You couldn't be authenticated

{
    "object": "result",
    "data": true
}

Path Params

your_org_name
string
required
object_class_id
string
required
 
Suggest Edits

Object Properties

 

The following sections describe the possible types of custom properties you can add to an object definition.

Base Property Options

The following base options are available when defining properties, unless otherwise noted. See individual properties for additional property-specific options.

*Bold options are required*

Name
Type
Default
Description

name

String

API name of property.

label

String

Property label that can be used in UI.

type

String

The property type. See individual property type details for more info.

description

String

Property description. This can be used for UI or for administrative purposes.

array

Boolean

false

If true, this property is an array of this type rather than a single value. This option can only be set when creating the property and cannot be changed.

uniqueValues

Boolean

false

Applies only if array: true. If true, values in array are guaranteed to be unique.

minItems

Integer

0

Applies only if array: true. The minimum number of items required in the array. Set to 0 for no minimum.

maxItems

Integer

100

Applies only if array: true. The maximum number of items allowed in the array. Cannot be greater than 1000.

maxShift

Boolean

false

Applies only if array: true. When true, shifts older items off of front of array when max items is reached rather than producing a kMaxAllowed fault.

canPush

Boolean

true

Applies only if array: true. If true, POST operations on the property can push values into the array.

canPull

Boolean

true

Applies only if array: true. If true, DELETE operations on property can remove items from the array by value or by array element _id

writeOnCreate

Boolean

true

Applies only if array: true. Allow values to be written to property array on document create.

readAccess

Integer

4

The access level require to read this property. See Access Control for available values.

writeAccess

Integer

6

The access level require to write to this property. See Access Control for available values.

acl

Document Array

Allows additional ACL to be specified for property. This acl merges with runtime acl to increase access to this property. Additive only -- these acl entries cannot lessen access to this property.

auditable

Boolean

false

When true, changes to this property will result in an audit record in the logs.

readable

Boolean

true

Allow this property to be read. When false, this property is not available through the API and is only available through scripts.

writable

Boolean

true

When true, this property is writable via the API. When false, this property is only writable through scripts.

creatable

Boolean

false

When true, this property is only writable on document creation.

removable

Boolean

false

If true, this property can be removed from a document using DELETE method. Otherwise, property can only be nullified.

optional

Boolean

false

If true, this property is not included in read operations unless explicitly included with the include option.

indexed

Boolean

false

If true, property is indexed and available for querying. There is a limit of 20 indexed properties per object.

unique

Boolean

false

If true, the property will be guaranteed unique. This option can only be set on property definition creation. There is a limit of 5 unique properties per object.

validators

Document Array

A list of validators applied to this property before writing. Failure to validate will result in akValidationError. See Property Validation Options for available validation options.

Property Validation Rules

When defining custom object properties, you can also specify validation rules to apply to your properties in the property definition validators option. You can specify multiple validation rules for a property.

When defined, these rules are evaluated prior to properties being written. Should validation fail for a property, the entire request will fail and a kValidationError fault will be returned for each validation error. When validations faults are returned, property paths are also returned with the faults. This is helpful when relaying validation errors to users in a client UI.

Validation rules take the form:

{
  "name": <validator name>,
  "description": <validator description>,
  "definition": { <validator definition> }
}

*Bold options are required*

Name
Type
Description

name

String

The name of an available validator for the property. See individual property details for available validators.

description

String

A description of the validator

definition

Document

A document specifying validator options (if available). See individual property validators for available options.

Property Type: any

An any property can store any user-defined object data. When defined, a json schema can be attached that will validate the
input. This is very handy for storing legacy, rapid prototyping, and for non-searchable/non-access controlled adhoc data.

Property Options

Name
Type
Default
Description

serializeData

Boolean

true

If true, property will be serialized and stored as a string. Note, when serialized, property cannot be used in query or aggregation.

maxSize

Integer

0

The maximum object size in bytes. Set to 0 for no maximum size.

Base property options not available:

  • array
  • uniqueValues
  • indexed
  • unique

Property Validators

Required
name: required

JSON Schema
name: json
defintion:

Option
Type
Description

schema

JSON Schema

A valid JSON Schema for validating the input against. See http://json-schema.org/examples.html for examples.

Property Type: binary

A binary property represents a raw buffer. For uploads and data with associated mimes such as video and images, use a File property. Scripting buffer objects can be natively stored and retrieved using the raw outputEncoding.

Property Options

Name
Type
Default
Description

serializeData

outputEncoding

base64

The encoding used to output the buffer (into a script or out through rest api). Valid values are:
base64, hex, array, utf8, raw.

maxSize

Integer

1000

The maximum buffer size in bytes, up to 1MB.

Base property options not available:

  • array
  • uniqueValues
  • indexed
  • unique

Property Validators

Required
name: required

 

Property Type: boolean

Boolean property values are simply true or false.

Property Type: date

DateTime values are sent through the API as string values formatted in simplified extended ISO format, which is always 24 characters long: YYYY-MM-DDTHH:mm:ss.sssZ (eg. 1966-07-12T16:34:01.000Z). The timezone is always zero UTC offset, as denoted by the suffix "Z". Though the parser will attempt to make sense of any sane date value, values should be sent in the above extended ISO format.

A Date property can also be configured as "Date only" for cases where the time zone is irrelevant, such as a birth dates. For these, the caller must send a string in the YYYY-MM-DD format, and responses will be in the same format (eg. 1973-07-16).

Property Options

Name
Type
Default
Description

dateOnly

Boolean

false

'If true, the input must be a string in the YYYY-MM-DD format, and responses will be in the same format (eg. 1973-07-16)'

Property Validators

Required
name: required

Date Validator
name: date
definition:

Option
Type
Default
Description

allowNull

Boolean

false

Allow null entries

min

Date

Earliest valid date

max

Date

Latest valid date

 

Property Type: document

A Document can act in two ways. When configured as an array, it is a collection of documents with shared properties. When not defined as an array, the document properties are implemented as children.

Documents whose definition is configured as an array have an _id property which can be used to retrieve, update or remove individual documents from the array. For example, the Organization roles are defined as a document array. Retrieving the _id of all org roles could be done as follows:

GET /orgs/5516ee1b34d8d934281699e3/roles?paths[]=_id

{
    "_id": "5516ee1b34d8d934281699e3",
    "object": "org",
    "roles": [{
        "_id": "000000000000000000000004"
    }, {
        "_id": "000000000000000000000005"
    }, {
        "_id": "000000000000000000000007"
    }]
}

Note

Notice the use of a relative path to the org roles identifiers in the query (paths[]=_id). Selection using paths, include and expand all work in this way.

An example of a non-array Document is the Account name property, having first and last child properties.

GET /accounts/me

{
    "_id": "5516ee2634d8d93428169c0e",
    "object": "account",
    "name": {
        "first": "Jonas",
        "last": "Salk"
    }    
}

Note

When ACLs and filters are applied at the document level, they affect access to all its children.

Discriminators

Some Document arrays contain a discriminator, such as Post and Comment bodies. Because these arrays carry documents with potentially varying properties, the name property is used as a discriminator. When creating a Post, for example, the discriminator must be included in the json body.

POST /c_vads/551f3515b8b206e835950b59/posts/c_heartrate

    {
        "body": [{
            "name": "c_datapoint",
            "c_value": 65
        }] 
    }

When updating a document array that has a discriminator, the _id of the segment is sufficient:

PUT /551f3a95b8b206e835950b6b

  {
      "body": [{
          "_id": "551f3aa2b8b206e835950b6d",
          "c_value": 67
      }] 
  }

Property Options

Name
Type
Description

properties

Property Definition Array

An array of property definitions. These can be properties of any type except Document.

Base property options not available:

  • uniqueValues
  • indexed
  • unique
  • auditable

Property Type: file

File types store binary data such as images or video. Each File type can be configured with multiple processors, which create streamable, named facets. Every File property has a default content facet at its root.

Streaming files is done in one of two ways, both of which begin by directly accessing a named facet using the path to the file property plus the facet name. For example, the Organization logo content can be accessed as follows:

GET /orgs/5516ee1b34d8d934281699e3/logo/content

The response depends on the value of the HTTP accept request header. If the header begins with application/json, the response is a json document containing a secure url property to the file stream:


{
"object": "facet",
"ETag": "594b69d035ac27c2e69ef053082eb6a3",
"creator": "5516ee2634d8d93428169c0e",
"height": 500,
"location": 4,
"mime": "image/jpeg",
"name": "content",
"size": 52586,
"state": 2,
"url": "https://cdn.medable.com/5516ee1b34d8d93428169/...",
"width": 622
}

If the accept header does not begin with application/json, the request will result in a 302 Found, with the Location response header having been set to the above url property.

Note

In cases where it's not possible to include HTTP request headers, such as an image tag, the Medable-Client-Key may be placed in the url as a query argument.

The Organization logo File property has a thumbnail facet, which can be accessed in much the same way, replacing content with thumbnail (GET /orgs/5516ee1b34d8d934281699e3/logo/thumbnail).

Reading a File without requesting a stream retrieves all of the File's facet information, which includes the root content and any available facets:

GET /orgs/5516ee1b34d8d934281699e3/logo
{
"ETag": "594b69d035ac27c2e69ef053082eb6a3",
"creator": "5516ee2634d8d93428169c0e",
"facets": [
{
"ETag": "5046104d05edf82e2a2c0d72118ca15b",
"creator": "5516ee2634d8d93428169c0e",
"height": 241,
"location": 4,
"mime": "image/jpeg",
"name": "thumbnail",
"path": "/orgs/5516ee1b34d8d934281699e3/logo/thumbnail",
"size": 16495,
"state": 2,
"width": 300
}
],
"height": 500,
"location": 4,
"mime": "image/jpeg",
"name": "content",
"path": "/orgs/5516ee1b34d8d934281699e3/logo/content",
"size": 52586,
"state": 2,
"width": 622
}

File States

File content and facets can be in the following states:

State Name Description
0 Pending The facet has been created, and the system is waiting for uploads.
1 Processing Sources are uploaded and are currently being processed into facets.
2 Ready The facet is ready for streaming.
3 Error There was an error processing the facet. A fault property is attached to the facet.
4 Dead The system will no longer attempt to process this facet. A fault property is attached to the facet.

Note

Requests for facets that are still in a pending or processing will result in a 202 kMediaNotReady fault. Clients should try again after a time. File processing time depends on the file size, type, number and type of facets, the and the facet storage location.

Private facets are only readable by the facet creator. As such, the uploaded content is completely isolated from view by other users, but can still be used as input to another process. The Conversation attachments File array is configured in this fashion, having a content facet that is configured to use an overlay png, combining it with a private original to produce a final image that is anonymized.

See File Uploads to find out how to upload media content.

Property Options

Name
Type
Description

processors

Document Array

Processors specify how your file will be processed. Available processor types are image, overlay, and passthru.

Base property options not available:

  • indexed
  • unique
 

Property Type: geometry

Geometry types store longitude latitude coordinates. There are two sub-types of Geo:

  1. Point [x, y]
    Two floats that represent a point (on a map or otherwise)

  2. Multi-Point [ Point, Point, Point, ...]
    an array of Points

Geometry types become very handy when you later want to check if a given x-y coordinate lies within the bounds of pre-defined area. For more info on this, see Geospatial Operators.

Property Options

Name
Type
Default
Description

geoType

string

"Point"

"Point" or "MultiPoint" stringEnum that defines what kind of coordinate data this prop will hold.

Property Type: list

List types store an array of references. Lists are used to model One-to-Many Relationships.

Property Options

Name
Type
Default
Description

sourceObject

String

0

The name of the source object for the list.

grant

Access Level (Integer) See Access Levels

This defines what level of access you have to the expanded list of object instances.

roles

ObjectID[]

This defines a set of roles to merge into the calling principal for access to the expanded object list.

skipAcl

Boolean

false

Select this if you'd like the matching to disregard all ACL rules.

where

String

A stringified where clause consisting of local instance properties linking the list references. Example: "{\"c_doc_ref\": \"{{input._id}}\" }"

linkedProperty

String

When set, connects the property to a top-level, indexed, readable, indexed, custom Reference in the sourceObject that points back to the current object.

When using a linked property, the where condition is augmented with {c_parent: "{{input._id}}"}, which in many case makes the where clause obsolete.

When using write-through, newly created children will automatically set the liked property to the identifier of the list holder.

To further secure the relationship, the child reference can be marked as cascadeDelete:true and writable:false.

readThrough

Boolean

false

Allows reading objects in a list using specific identifiers and overriding list rules (defaultAcl, grant, roles)

writeThrough

Boolean

false

Allows creating and updating objects in a list using specific identifiers and overriding list rules (createAcl/defaultAcl, grant, roles)

updateOnWriteThrough

Boolean

false

When true, write-through events bubble up to the current instance and modify the updated date, firing any triggers and updating the ETag where required.

inheritInstanceRoles

Boolean

false

When true, instance roles held by the caller on the current instance are applied to the list instances.

createAcl

Object[]

[]

An overriding set of acl rules to apply to creation of child object instances when write-through is enabled.

defaultAcl

Object[]

[]

An overriding set of acl rules to apply to reading of child object instances when read/write-through is enabled.

Base property options not available:

  • array
  • indexed
  • unique
  • writable
  • minItems
  • maxItems
  • canPull
  • canPush
  • maxShift
  • writeOnCreate

Property Type: number

A Number value can be configured to hold integer or float values, with minimum and/or maximum values.

Property Validators

Required
name: required

Number Validator
name: number
definition:

Name
Type
Default
Description

allowNull

boolean

false

Allow null entries

min

integer

Minimum value

max

integer

Maximum value

allowDecimal

boolean

true

Allow float values

Allow Level Validator
name: allowLevel
definition:

Name
Type
Default
Description

includeNoAllow

boolean

false

Allow acl.AccessLevels.NoAllow. If false, acl.AccessLevels.Public is the minimum allowed

defaultValue

integer

an optional default value

Coordinate Validator
name: coordinate
definition:

Name
Type
Default
Description

min0

integer

min value

max0

integer

max value

min1

integer

min value

max1

integer

max value

allowDecimal0

boolean

true

Allow float values

allowDecimal1

boolean

true

Allow float values

Enum Validator
name: numberEnum
definition:

Name
Type
Default
Description

values

array

An array of possible entries

 

Property Type: objectid

An ObjectId is a 12-byte BSON type, used to represent the _id property of contexts, posts, body segments, document array element identifiers, and others. When retrieved using the API, these values are represented in the response as a 24-byte hexadecimal string value.

Property Validators

Required
name: required

ID Enum Validator
name: idEnum
definition:

Name
Type
Default
Description

idEnum

boolean

true

true if element exists in the list of possible objectId's

Suggest Edits

Reference

 

Property Type: reference

A Reference property is a structure that exposes the object, identifer of another object instance. Some references can be expanded , allowing an object instance to be read through another.

Property ACLs can be attached to references in order to allow greater access to expanded properties than would normally be allowed. For example, the Patient File Object account property exposes the name property of the referenced account when expanded to anyone who is Connected to the Patient File.

Custom reference properties can be configured to allow the reference identifier to be updated, but only if the caller has the required referenceAccess to the instance being referenced. References can also be configured to include a static list of properties, or disallow expansion entirely.

Property Options

Option
Type
Default
Description

expandable

Boolean

false

If true, this property can be expanded using "expand" options

autoCreate

Boolean

false

If true, a referenced object is auto-created, owned by the owner of the host context (in the case of account, the account holder)

grant

Number

acl.AccessLevels.NoAllow

Applies to expansions. The access level granted to the calling principal through expansion. Warning! This option can expose private context details. Consider using object pacls instead, and leave the grant level low.

sourceObject

String

Applies to expansions. The name of the object from which to expand.

paths

String

Applies to expansions. A list of fixed property names to load if the property is expanded. If set, access is always granted to these paths.

referenceAccess

Number

acl.AccessLevels.Share

The access required by the calling principal on the referenced context in order to set the reference _id.

pacl

Document

Adds augmented access to individual properties in the expanded object.

writeThrough

Boolean

false

Allows updating referenced objects, overriding access control using custom defaultAcl, gran and roles.

inheritInstanceRoles

Boolean

false

When true, instance roles held by the caller on the current instance are applied to the reference when expanded or updated using write-through.

defaultAcl

Object[]

[]

An overriding set of acl rules to apply to referenced instances when expandable or write-through is enabled.

Property Type: string

Strings represent a text value and can be configured with validators to limit input using regular expressions, and to enforce minimum and maximum lengths.

Property Options

Name
Type
Default
Description

trim

boolean

false

Trims the input string prior to validation but after writers.

lowercase

boolean

false

Lowercase the input string prior to validation but after writers.

uppercase

boolean

false

Uppercase the input string prior to validation but after writers.

Property Validators

Required
name: required

String Validator
name: string
definition:

Name
Type
Default
Description

min

integer

0

Minimum length of string

max

integer

Maximum length of string

allowNull

boolean

false

Allow null values

allowEmpty

boolean

false

Allow 0-length strings

Printable String Validator
name: printableString
definition:

Name
Type
Default
Description

anyFirstLetter

boolean

true

Allow the first letter of the string to be non-alphanumeric.

allowNumberAsFirstLetter

boolean

true

Allows a number as the first letter of the string.

min

integer

0

min length

max

integer

max length

String Enum Validator
name: stringEnum
definition:

Name
Type
Default
Description

values

array

An array of possible entries.

Email Validator
name: email
definition:

Name
Type
Default
Description

allowNull

boolean

true

Allow blank or null entries

Locale Validator
name: locale
definition:

Name
Type
Default
Description

allowNull

boolean

false

Allow blank or null entries

Password Strength Validator
name: passwordStrength
definition:

Name
Type
Default
Description

minScore

integer

The minimum password score requirement (based on zxcvbn)

Phone Number Strength Validator
name: phoneNumber
definition:

Name
Type
Default
Description

allowNull

boolean

false

Allow null entries.

requireMobile

boolean

false

If true, requires the number to be a mobile number.

allowedCountries

array or strings

List of allowed countries

URL Validator
name: url
definition:

Name
Type
Default
Description

allowNull

boolean

false

Allow null values

allowEmpty

boolean

false

Allow 0-length strings

webOnly

boolean

true

Url must be a web url, beginning with http:// or https://

webSecure

boolean

Applies when webOnly is true. If present, url must either be https:// (true) or http:// (false). Omitting this property allows either.

Pattern Validator
name: pattern
definition:

Name
Type
Default
Description

allowNull

boolean

false

Allow null values

allowEmpty

boolean

false

Allow 0-length strings

pattern

regex

The regex pattern to test against the incoming string value

Suggest Edits

Object Types

Sub-classing objects

 

In your data modeling, you may find that you want to define an object class that inherits all properties from another. For example, you might have a generic c_assessment class with properties like c_patient and more specific classes like c_blood_test that has all the properties of c_assessment but also a set of more specific properties like c_blood_type.

To create an object type, you simply add the object type definitions into the objectTypes array of an object's definition. These types will inherit all the properties from the super-class (or super-type).

The properties that define an object type are as follows:

Object Type Properties

Name
Type
Description

name

String

The API name for the object type

label

String

The human readable label for the object type

properties

Property Definition Array

The array of property definitions for properties specific to this object type

Note

Once an object type is defined, the type property becomes required when creating instances of the object. The type property is populated with the name of the object type you are creating.

Examples

In this example, we've created the object class c_assessment and set the proper ACL's. We've also added a property to this object that all of this object's types will share: c_patient. This is because all assessments will be made on a particular patient, no matter what kind of assessment it is.

GET /objects/5951719d514ef101000216cf
{
    "_id": "5951719d514ef101000216cf",
    "access": 7,
    "allowConnections": true,
    "allowTransfers": true,
    "connectionOptions": {
        "requireAccept": true,
        "requiredAccess": 5,
        "sendNotifications": true
    },
    "createAcl": [
        {
            "_id": "5951719dfc65ed0100e62068",
            "allow": 1,
            "target": "000000000000000000000003",
            "type": 1
        }
    ],
    "created": "2017-06-26T20:42:05.183Z",
    "creator": {
        "_id": "5771495a1d0c03a53ce83f1a",
        "object": "account",
        "path": "/accounts/5771495a1d0c03a53ce83f1a"
    },
    "defaultAcl": [
        {
            "_id": "5951719dfc65ed0100e62069",
            "allow": 7,
            "target": null,
            "type": 4
        }
    ],
    "favorite": false,
    "feedDefinition": [],
    "label": "Assessment",
    "lookup": "5951719d514ef101000216cf",
    "name": "c_assessment",
    "object": "object",
    "objectTypes": [],
    "pluralName": "c_assessments",
    "properties": [
        {
            "_id": "595171e811f6710100683480",
            "acl": [],
            "auditable": false,
            "autoCreate": false,
            "cascadeDelete": true,
            "creatable": false,
            "expandable": true,
            "grant": 0,
            "indexed": true,
            "label": "Patient",
            "name": "c_patient",
            "optional": false,
            "pacl": [],
            "paths": [],
            "readAccess": 4,
            "readable": true,
            "referenceAccess": 5,
            "removable": false,
            "sourceObject": "account",
            "type": "Reference",
            "unique": false,
            "validators": [
                {
                    "_id": "595171e811f6710100683481",
                    "name": "required"
                }
            ],
            "writable": true,
            "writeAccess": 6
        }
    ],
    "shareChain": [
        5,
        4,
        2
    ],
    "updated": "2017-06-26T20:43:21.022Z",
    "updater": {
        "_id": "5771495a1d0c03a53ce83f1a",
        "object": "account",
        "path": "/accounts/5771495a1d0c03a53ce83f1a"
    }
}

You'll notice that the objectTypes value in the JSON result above is an empty array. We're going to add a c_blood_test object type to this array.

POST /objects/5951719d514ef101000216cf/objectTypes
{
    "label":"Blood Test",
    "name":"c_blood_test",
    "properties": [
        {
            "label":"Blood Type",
            "name":"c_blood_type",
            "type": "String",
            "validators": [
                {
                    "name": "required"
                }
            ]
        }
    ]
}

Now, the objectTypes array contains the c_blood_test definition we just created.

GET /objects/5951719d514ef101000216cf/objectTypes
{
    "data": [
        {
            "_id": "5951751611f6710100683fdc",
            "label": "Blood Test",
            "name": "c_blood_test",
            "properties": [
                {
                    "_id": "5951751611f6710100683fdd",
                    "acl": [],
                    "array": false,
                    "auditable": false,
                    "canPull": true,
                    "canPush": true,
                    "creatable": false,
                    "indexed": false,
                    "label": "Blood Type",
                    "lowercase": false,
                    "maxItems": 100,
                    "maxShift": false,
                    "minItems": 0,
                    "name": "c_blood_type",
                    "optional": false,
                    "readAccess": 4,
                    "readable": true,
                    "removable": false,
                    "trim": false,
                    "type": "String",
                    "unique": false,
                    "uniqueValues": false,
                    "uppercase": false,
                    "validators": [
                        {
                            "_id": "5951751611f6710100683fde",
                            "name": "required"
                        }
                    ],
                    "writable": true,
                    "writeAccess": 6,
                    "writeOnCreate": true
                }
            ]
        }
    ],
    "hasMore": false,
    "object": "list"
}

We can now create a c_assessment object instance of type c_blood_test:

POST /c_assessments

{
    "c_patient":"5771495a1d0c03a53ce83f1a",
    "type":"c_blood_test",
    "c_blood_type":"Type A"
}

The resulting instance of c_assessment is of type: c_blood_test and contains both the base property of c_patient and the c_blood_test type property c_blood_type.

{
    "_id": "59517718cfc40501006da501",
    "access": 7,
    "c_blood_type": "Type A",
    "c_patient": {
        "_id": "5771495a1d0c03a53ce83f1a",
        "object": "account",
        "path": "/accounts/5771495a1d0c03a53ce83f1a"
    },
    "created": "2017-06-26T21:05:28.068Z",
    "creator": {
        "_id": "5771495a1d0c03a53ce83f1a",
        "object": "account",
        "path": "/accounts/5771495a1d0c03a53ce83f1a"
    },
    "favorite": false,
    "object": "c_assessment",
    "owner": {
        "_id": "5771495a1d0c03a53ce83f1a",
        "object": "account",
        "path": "/accounts/5771495a1d0c03a53ce83f1a"
    },
    "shared": false,
    "type": "c_blood_test"
}
Suggest Edits

Access Control

 

Access control lists (ACLs) allow you to define fine-grained access to object instances and their properties directly in your data model.

ACLs are composed of access control definitions. These definitions take the following forms:

{
  "type": <access target type>,
  "target": <access target identifier>,
  "allow": <access level>
}

These definitions are evaluated and applied to the specified targets at runtime.

Access Control Definition Properties

Name
Type
Description

type

Integer

Integer representing the type of entity this ACL applies to at runtime. See Access Types

target

ObjectId

The _id of the role or account that of the ACL target. Not used when type is Self or Owner.

allow

Integer

Integer representing access level being granted to target. Not used in create ACL. See Access Levels

Access Types

Type
Name
Description

1

Account

Target type of Account -- includes anonymous and public principals.

2

Self

Applies to ACL on Account object only. Access principal is the same as the Account instance being accessed.

3

Role

Target type of org role

4

Owner

Access principal is the object instance owner.

5

Access

For share ACL only, allows the access target to be an access level. This overrides the share chain behaviour and enables more fine-tuning.

Access Levels

Level
Name
Description

1

Public

A principal with this access can read public data (eg, Org details).

2

Connected

Granted when making Connections and typically provides read access to context properties.

3

Reserved

Reserved for a future use

4

Read

Grants access to private context properties. This is default access level required for new custom properties.

5

Share

Those with share access can create connections to a context using object’s Share Chain

6

Update

Update access typically provides write access to context properties.

7

Delete

Grants access to delete delete/archive a context.

8

Script

The highest assignable access level, it can only be granted at runtime in a script.

Defining ACL

By default, Cortex enforces a no-access sharing model. This means that without defined ACL, users cannot create, read, update, or delete any data through the API. That is, until the ability to do so is granted through ACL definitions in custom objects and in extensible standard objects.

Standard objects such as the Account Object come pre-defined with Create ACL and Default ACL that enforce a private sharing model.

In a private-sharing model, data is only available to the creator/owner and no one else. In this model, there are only two ways for a user to gain access to another user's data:

  1. The owner of the data shares that data with another user directly using Connections.
  2. Access to the data is granted to a subset of users (such as through ACLs)

The following ACL definitions make up a typical private-sharing implementation for an object.

Create ACL

createAcl: [{
  "target": "000000000000000000000003",
  "type": 1
}]

Here, the type: 1 specifies the target is an Account, and the target: "000000000000000000000003" is the system identifier for any user in the org. So this ACL is specifying that any authenticated user can create instances of this object.

Default ACL

defaultAcl: [{
  "allow": 7,
  "type": 4
}]

Here, the type: 4 is specifying that the target is the instance Owner, and the allow: 7 specifies that the Owner is granted Delete access.

Share Chain

shareChain: [6, 5, 4, 2]

This share chain specifies that access levels of update (6), share (5), read (4), and connected (2) can be used in connections. Because it is a share chain, a user can create a connection with one of these allow levels as long as it is less than his/her own.

Create ACL

Create ACLs determine who in an Organization can create new object instances. Conversations, for example, can only be created by accounts with the Provider role. An object's create acl can be defined in custom objects and augmented or even overwritten in extensible standard objects.

In the case of Create ACL, allow is not provided in the definition since create access is already implied.

Default ACL

Each Object has it's own set of default rules that determine the level of access users get to object instances. For example, the Account Object default acl allows the account holder Update access to themselves. These defaults can be defined in custom objects and augmented or even overwritten in extensible standard objects.

Share ACL

Share ACLs define how an object instance can be shared. The target in a share ACL entry can be an account, role, owner, or another access level. The allow in a share ACL entry then specifies what role or access level that target is allowed to grant when sharing an object instance via a connection. When share ACL rules are defined, share chains no longer apply.

Example Share ACL

shareAcl:[{
    "type": 5,
    "target": 7,
    "allow": 6
}]

Here, the type: 5 is specifying the target is an access level. This means that a user with an access level of 7 (Delete) to the instance can grant up to access level 6 (Update) to another user via a connection.

shareAcl: [{
  "type": 4,
  "allow": "000000000000000000000005"
}]

Here, the type: 4 is specifying the target is the instance owner and that the owner can grant the provider role (role _id "000000000000000000000005") via a connection. This means that any defaultAcl defined for the provider role in the object definition will be granted to the connected user for that object instance even though they may not have the provider role assigned to their user account.

shareAcl: [{
  "type": 3,
  "target": "5532e499540b0183799b4ee5"
  "allow": "58e96eb0105ddf010067046b"
}]

Here, the type: 3 is specifying the target is a role. We've created some custom roles of Manager (role _id "5532e499540b0183799b4ee5") and Reporter (role _id "58e96eb0105ddf010067046b"). In the share ACL rule, we are specifying that the Manager role can grant the Reporter role to another user for an object instance via a connection.

Share Chains

The share chain for each Object controls the access level that can be granted to a user through a Connection. A user with
enough access to create a Connection can grant any level of access in the object's Share Chain as long as it is lesser than
their own.

For example, a user who creates a Patient File is granted Delete access through the object's default ACL. That use can
then grant others Share or Connected access to the context. Subsequently, a connected invitee with Share access could
re-share the context with others, but only grant Connected access.

The share chains for each object are listed in their descriptions.

User Roles

There are three standard roles: Admin, Provider and Developer. An Organization can create custom roles, and assign access
controls to these. Custom roles can be also be includes within each other. All accounts holder a role are also assumed to
hold the included roles.

Property ACLs

Object properties have ACLs that determine the access required to create, read, update and delete properties. An Organization can
also augment read and update access settings for individual properties with custom ACLs. Commonly, properties required
Connected access to read and Update access to update.

Suggest Edits

Query Arguments

 

Objects can be queried using the available query arguments, allowing developers to easily search large amounts using the API.

Query arguments are applied in the following order: where, sort, skip, limit

Query Arguments

Name
Description
Example

Accepts A JSON object containing operators and expressions used to limit the search results.

where={“$and”: [{“created”: {“$gt”: “2015-01-01T00:00:00.000Z”}}, {“created”: {“$lt”: “2015-06-01T00:00:00.000Z”}}]}

Used to sort results, can be an indexed property name or a named grouping (when group is used). Also accepts a JSON object containing one or more properties, the values of which must be 1 for ascending and -1 for descending.

sort=posts or sort={“posts”: 1, “_id”: 1}

An integer representing the number of results to skip. Useful for paging where mapping or groupings have been applied, or where search the search criteria cannot be paged using unique fields.

skip=100

An integer representing the number of results to return.

limit=20

The where argument limits the resulting document list using search criteria applied against indexed properties.

?where={<query conditions>}

See Query Operators for more details and examples of available conditions.

Examples

For example, the following call finds all accounts where the last name starts with the letter s (case-insensitive) and sorts by last name, then by first name.

GET /accounts?where={"name.last": {"$regex": "/^s/i"}}
{
    "data": [
        {
            "_id": "5888b91d35f8c91536c6ddea",
            "access": 6,
            "c_enrollments": [],
            "c_study_groups": [],
            "created": "2017-01-25T14:41:33.297Z",
            "email": "john@medable.com",
            "favorite": false,
            "gender": "m",
            "inherited_roles": [
                "000000000000000000000007",
                "000000000000000000000006"
            ],
            "key": {
                "fingerprint": "8e53d430-e30c-11e6-aaeb-99172490c13b",
                "secret": "heBcf2Wgh6hjezADTAc88wHJNGcJgwUd"
            },
            "locale": "en_US",
            "locked": false,
            "mobile": "+12223334449",
            "name": {
                "first": "John",
                "last": "Silver"
            },
            "object": "account",
            "roles": [
                "000000000000000000000004"
            ],
            "shared": false,
            "state": "verified",
            "updated": "2017-01-25T14:42:54.970Z",
            "updater": {
                "_id": "5888b91d35f8c91536c6ddea",
                "object": "account",
                "path": "/accounts/5888b91d35f8c91536c6ddea"
            }
        }
    ],
    "hasMore": false,
    "object": "list"
}

Sorting can be applied to indexed properties, or to any named property when a grouping is applied. The value can be a single property name sort=total, or a JSON object containing
one or more property names with either 1 (ascending) or -1 (descending) as the value.

?where={<query conditions>}&sort=<property>

Or when specifying the sort order:

?where={<query conditions>}&sort={<property>: <sort order>}

Or sorting by multiple properties:

?where={<query conditions>}&sort={<property1>: <sort order>, <property2>: <sort order>, ...}

Examples

The following shows an example of sorting a list of accounts by last name then by first name.

GET /accounts/?paths[]=name&sort={"name.last": 1, "name.first": 1}
{                
    "data": [
        {
            "_id": "507f1f77bcf86cd799439011",
            "name": {
                "first": "John",
                "last": "Smith"
            },
            "object": "account"
        },
        {
            "_id": "55ff9db67a00a89c14aa31a6",
            "name": {
                "first": "Stan",
                "last": "Smith"
            },
            "object": "account"
        },
        {
            "_id": "507f191e810c19729de860ea",
            "name": {
                "first": "Jane",
                "last": "Svenson"
            },
            "object": "account"
        },                        
        ...  
  ],
  "hasMore": true,
  "object": "list"
}

The skip argument lets you specify a number of results to skip in your result set.

?where={<query conditions>}&skip=<positive integer>

Examples

For example, if you have a result set of 200, and you specify skip=100, you would receive results 101-200.

GET /accounts/?paths[]=name&skip=2

{                
    "data": [
        {
            "_id": "507f191e810c19729de860ea",
            "name": {
                "first": "Jane",
                "last": "Svenson"
            },
            "object": "account"
        }                       
  ],
  "hasMore": false,
  "object": "list"
}

/* if the full result set was
[
  {
    "_id": "507f1f77bcf86cd799439011",
    "name": {
      "first": "John",
      "last": "Smith"
    },
    "object": "account"
  },
  {
    "_id": "55ff9db67a00a89c14aa31a6",
    "name": {
      "first": "Stan",
      "last": "Smith"
    },
    "object": "account"
  },
  {
    "_id": "507f191e810c19729de860ea",
    "name": {
      "first": "Jane",
      "last": "Svenson"
    },
    "object": "account"
  }                       
]
*/

Limitations of paging with skip

Paging using skip should only be used for small result sets of a few hundred or less. For paging larger result sets, see Paging

The limit argument allows you to specify a number of results to return, e.g. limit=2. The default limit for an API request is 100. The max limit is 1000.

?where={<query conditions>}&limit=<positive integer>

If you are dealing with a result set larger than 1000, you should either narrow your result set with a more specific where clause or use pagination to page through your full result set.

Examples

GET /accounts/?paths[]=name&limit=2

{                
    "data": [
        {
            "_id": "507f1f77bcf86cd799439011",
            "name": {
                "first": "John",
                "last": "Smith"
            },
            "object": "account"
        },
        {
            "_id": "55ff9db67a00a89c14aa31a6",
            "name": {
                "first": "Stan",
                "last": "Smith"
            },
            "object": "account"
        }
  ],
  "hasMore": true,
  "object": "list"
}

Most API calls that result in a list response can be paged by using the hasMore property when it is true. Paging results can be accomplished using limit and where query arguments or a combination of where, limit and skip query arguments.

The recommended method for paging is using indexed, unique identifiers such as _id, sorting by the identifier and applying a where argument. For example:

?where={"_id": {"$gt": "561b5a700000000000000000"}}&sort={"_id": 1}

If forced to sort by non-unique fields, like name.last, it is possible to fall back on using the skip argument for paging, though it is not as efficient as using a unique indexed field. Additionally, paging using skip is only effective for small result sets (e.g. less than a few hundred records).

In the below example, we have a custom "Conversation" object. Suppose there are 20 conversations available to a user. An initial call to GET /conversations?paths[]=_id&limit=2&sort={"_id": 1} results in the following response:

GET /c_conversations?paths[]=_id&limit=2&sort={"_id": 1}

{
    "data": [
        {
            "_id": "551c76c3bad12f302b343481",
            "object": "c_conversation"
        },        
        {
            "_id": "551c76c4bad12f302b343489",
            "object": "c_conversation"
        }
    ],
    "hasMore": true,
    "object": "list"
}

The response's hasMore property is true, so the caller knows there are more results. The last _id in the list is used in the next where argument like this:

GET /conversations?paths[]=_id&limit=2&where={"_id": {"$gt": "551c76c4bad12f302b343489"}}&sort={"_id": 1}

{
    "data": [
        {
            "_id": "551c76c3bad12f302b343492",
            "object": "c_conversation"
        },        
        {
            "_id": "551c76c4bad12f302b343511",
            "object": "c_conversation"
        }
    ],
    "hasMore": true,
    "object": "list"
}

List Property Paging

Lists of contexts can be paged by prefixing query arguments with the property name. For example:

GET /c_patientfiles/550891732390ac1832f3317f/?paths[]=connections.access&connections.where{"_id":{"$gt":"550b9a25c59c1ef032ab641c"}}

{
    "_id": "550891732390ac1832f3317f",
    "object": "c_patientfile",
    "connections": {
        "object": "list",
        "hasMore": "false",
        "data: [{
             "_id": "551ce5dfcd3227a41dfa7e9d",
             "object": "connection",
             "access": 2            
         }]
     }     
 }
Suggest Edits

Query Operators

 

Query operators can be used to construct query conditions in order to find data. Query operators are typically applied to a property and take a value or a document defining the conditions of the operation.

For example:

{<property>: {<operator>: value}}

Or:

{<property>: {<operator>: {<option>: <value>, <option>: value, ...}}}

Or, in the case of logical operators (e.g. $and, $or), the operator takes an array of expressions:

{<operator>: [{<expression>}, {<expression>}, ...]}

Usage

Query operators can be used in a where query argument or in a $match pipeline stage .

When used in a where query argument, the request looks similar to the following:

GET /<object>?where={<query conditions>}

When used in a $match pipeline stage, the request looks similar to the following:

GET /<object>?pipeline=[{"$match":{<query conditions>}}]

Query Operator Types

Type
Description

For filtering results based on value comparisons.

Join query clauses together or invert the meaning of a query expression

Filter results based on the result of a regular expression

Find locations within a distance of a central location.

Match on arrays, elements in an array, or size of arrays.

Suggest Edits

Comparison Operators

 
Operator
Description
Example

$eq

Selects documents where the value of the property is equal to the passed in value.

{“c_bpm”: {“$eq”: 70}}

$gt

Selects documents where the value of the property is greater than the passed in value.

{“c_bpm”: {“$gt”: 70}}

$gte

Selects documents where the value of the property is greater than or equal to the passed in value.

{“c_bpm”: {“$gte”: 70}}

$lt

Selects documents where the value of the property is lesser than the passed in value.

{“c_bpm”: {“$lt”: 70}}

$lte

Selects documents where the value of the property is lesser than or equal to the passed in value.

{“c_bpm”: {“$lte”: 70}}

$ne

Selects documents where the value of the property is not equal to the passed in value.

{“c_bpm”: {“$ne”: 70}}

$in

Selects documents where the property matches any of the passed in values.

{“c_bpm”: {“$in”: [65, 66, 67, 68, 69, 70]}}

$nin

Selects documents where the property matches none of the passed in values.

{“c_bpm”: {“$nin”: [65, 66, 67, 68, 69, 70]}}

Suggest Edits

Logical Operators

 
Operator
Description
Example

$and

Selects documents where all passed in conditions are met.

{“$and”: [{“c_bpm”: {“$gt”: 70}}, {“c_bpm”: {“$lt”: 100}}] }

$or

Selects documents where any passed in conditions are met.

{“$or”: [{“c_bpm”: {“$gt”: 70}}, {“c_bmi”: {“$gt”: 24.9}}] }

$not

Evaluates to true if the property or expression evaluates to false.

{“$not”: “c_active”}

$nor

Selects documents where none of the passed in conditions are met.

{“$nor”: [{“c_bpm”: {“$gt”: 70}}, {“c_bmi”: {“$gt”: 24.9}}] }

Suggest Edits

Evaluation Operators

 
Operator
Description
Example

$regex

Selects documents where the string property matches the passed in regular expression.

{“name.first”: {“$regex”: “/^james/i”}}

Suggest Edits

Geospatial Operators

 
Operator
Description
Example

$within

Selects documents with geospatial data that exists entirely within a specified shape.

{"c_location": {"$within": {"$center": [-122.143019, 37.441883], "$radius": 10}}}

Suggest Edits

Array Operators

 
Operator
Description
Example

$all

Selects documents where the array property contains all of the passed in values.

{“roles”: {“$all”: [“000000000000000000000007”, “0123456789ab0123456789ab”]}}

$elemMatch

Selects documents where all properties of an array of document properties match the passed in expression. $elemMatch does not limit the results within the array, but filters the entire document for contained entries.

{“c_docs”: {“$elemMatch”: {“c_foo”: “yes”, “c_bar”: true}}}

$size

Selects documents where the size of the array property matches the passed in values.

{“c_arr”: {“$size”: 20}}

Suggest Edits

Property Selection

 

Selecting context response properties using the API is accomplished using paths, include and expand query arguments.

paths

string[]

An array of properties to which the response should be limited.

include

string[]

An array of properties marked as optional that should be included in the response.

expand

string[]

An array of expandable reference that should be expanded in the response.

You can specify any of the above query arguments multiple times. For example, if you need to expand multiple properties, you can do so with the following query string.

?expand[]=account&expand[]=c_customProperty1&expand[]=c_customProperty2

Examples

The example below shows:

  • A reference automatically expanded by selecting a path in the referenced context (creator.name.first).
  • A response limited to the paths specified by the paths[] query arguments.
  • An explicit reference expansion using expand[]=account.
  • An optional path included with include[]=connections.
  • An implicitly included optional path through the use of paths[]=posts;
$.ajax({
	url: "https://api.dev.medable.com/example/patientfiles/550891732390ac1832f3317f?expand[]=account&include[]=connections&paths[]=posts&paths[]=age&paths[]=name.first",
	type: "GET",
	contentType: "application/json; charset=UTF-8",
	dataType : "json",
	headers: {
		"Medable-Client-Key": "GsAqlhnIMzrDeD8V2MBQWq"		
	}
});
MDAPIParameters* parameters = [MDAPIParameterFactory parametersWithParameters:
                                   [MDAPIParameterFactory parametersWithExpandPaths:@[ kAccountKey ]],
                                   [MDAPIParameterFactory parametersWithIncludePaths:@[ kConnectionsKey ]],
                                   [MDAPIParameterFactory parametersWithLimitPaths:@[ kPostsKey, kAgeKey, [MDAPIPathFactory pathStringWithComponents:@[ kNameKey, kFirstNameKey ]]] ],
                                   nil];
  
[[MDAPIClient sharedClient]
     patientFileWithId:[MDObjectId objectIdWithString:@"550891732390ac1832f3317f"]
     parameters:parameters
     callback:^(MDPatientFile *patientFile, MDFault *fault)
     {
         if (fault)
         {
             // Fault handling
         }
     }];
{
    "_id": "550891732390ac1832f3317f",
    "object": "patientfile",
    "account": {
        "_id": "550b82336390d9cc34fdd1f0",
        "access": 1,
        "name": {
            "first": "Phineas",
            "last": "Gage"
        },
        "object": "account",
        "roles": []
    },
    "age": 25,    
    "connections": [
        {
            "_id": "550b9a25c59c1ef032ab641c",
            "object": "connection",
            "access": 2,
            "context": {
                "_id": "550891732390ac1832f3317f",
                "object": "patientfile",
                "path": "/patientfiles/550891732390ac1832f3317f"
            },
            "created": "2015-03-20T03:55:17.000Z",
            "creator": {
                "_id": "4578616d706c652055736572",
                "object": "Account",
                "path": "/accounts/4578616d706c652055736572"
            },            
            "state": 1,
            "target": {
                "email": "patient@example.com"                
            }
        }
    ],
    "creator": {
        "_id": "4578616d706c652055736572",
        "name": {
            "first": "James"
        },
        "object": "account"
    },
    "name": {
        "first": "Phineas"
    }      
    "posts": []
}

Another example would be to automatically expand into the account reference and limit the properties to first name of the referenced account. The account name may not be accessible to the caller, but the Patient File account property reference has an ACL that allows the name to be read by caller with a Connection to the patient file:

// GET /patientfiles/550891732390ac1832f3317f?paths[]=account.name.first

{
    "_id": "550891732390ac1832f3317f",
    "account": {
        "_id": "550b82336390d9cc34fdd1f0",
        "name": {
            "first": "Phineas"
        },
        "object": "account"
    },
    "object": "patientfile"
}

Limiting Response Properties

Clients can shrink responses by limiting the properties returned by an API request using the paths query argument. Sub paths
must be in dot syntax (eg. name.first) and must exist in the object definition.

  • Object responses always include the _id and object properties.
  • Selecting an optional property using paths automatically includes it.
  • Selecting a path in a reference is possible (eg creator.name.first), automatically expanding the referenced context.

Expanding References

References marked as expandable can be expanded into full objects. This can result in less API calls when the client
wants to access information in the referenced object.

Depending on the reference property definition, using expand[] may limit the resulting expansion to a set of paths,
may grant greater context access than the caller would normally have or allow greater access to a set of properties.

For more information about configuration options, see the section about References.

Optional Properties

Some object properties are marked as optional. Typically, these are non-crtical properties that would be expensive to include
in every set of responses. For example, the connections and posts properties of objects are optional so wouldn't be
included in the result of a call to GET /patientfiles. To retrieve properties marked as optional, use the include[]
query argument.

When using paths[], included optional properties will be part of the response.

List Property Selections

Properties that return a list of contexts, such as posts and connections can have selection arguments passed by prefixing
them with the property name. For example:

// GET /patientfiles/550891732390ac1832f3317f/connections?paths[]=access

{
    "_id": "550891732390ac1832f3317f",
    "object": "patientfile",
    "connections": {
        "object": "list",
        "hasMore": "false",
        "data: [{
             "_id": "550b9a25c59c1ef032ab641c",
             "object": "connection",
             "access": 2            
         }]
     }         
}
Suggest Edits

Property Access

 

The Medable API affords developers the ability to access and update property data in flexible and convenient ways.

Although Property Selection can reduce the number of paths returned while maintaining the structure of the document,

// GET /accounts/5516ee2634d8d93428169c0e?paths[]=name.first

{
    "_id": "5516ee2634d8d93428169c0e",
    "name": {
        "first": "Jonas"
    },
    "object": "account"
}

A single property can also be directly accessed, resulting in a result response.

// GET /accounts/5516ee2634d8d93428169c0e/name/first

{
    "object": "result",
    "data": "James"
} 

A property within a document array can be directly accessed, using its _id ("551f34c8b8b206e835950b57"). For example, retrieving the name of a custom role:

// GET /orgs/5516ee1b34d8d934281699e3/roles/551f34c8b8b206e835950b57/name

{
    "object": "result",
    "data": "Care Giver"
} 

Properties may be updated in the same way. The following are both valid ways to update the name of the above role:

// PUT /orgs/5516ee1b34d8d934281699e3

Request:
    {
        "roles": [{
            "_id": "551f34c8b8b206e835950b57",
            "name": "Third Party"
        }]
    }
Response:
    {
        "_id": "5516ee1b34d8d934281699e3",
        "object": "org",        
        "code": "example",        
        "roles": [{
            "_id": "551f3515b8b206e835950b59",
            "name": "Care Giver",
            "all": [],
            "include": []            
            },
            ...
        ],
        ...                
    }

The above response includes the entire updated context.

// PUT /orgs/5516ee1b34d8d934281699e3/roles/551f34c8b8b206e835950b57/name

Request:
    "Third Party"
Response:
    {
        "object": "result",
        "data": "Third Party"
    } 

Property and Document arrays can be configured to allow overwrite, append-only, and/or pull. Arrays can also be configured to ensure unique values within the array, or in the case of a Document array, a property can have a validator that ensures it is unique within the rest of the parent array's documents.

  • Appending items to an array using the API must be done using the POST method.
  • Overwriting an array is done using PUT.
  • Array elements can be directly access by index (GET /orgs/5516ee1b34d8d934281699e3/roles/0).
  • Array elements cannot be updated by index.
  • When removing elements from a document array, use the _id (DELETE /orgs/5516ee1b34d8d934281699e3/roles/551f34c8b8b206e835950b57)
  • When removing elements from a primitive array, all matchinge values are removed (DELETE /c_custom/c_tags/MyTag)
Suggest Edits

Pipeline Aggregation

 

Pipeline aggregation allows for querying, aggregating, and transforming data in multiple stages in real-time through a single API request. While query arguments allow for making simple, single-stage queries through the API, pipelines allow for more complex searches, aggregations and transformations.

To leverage pipeline aggregation via the API, simply pass a pipeline query argument with the request. The pipeline query argument is an array of pipeline stages that execute in order. Each stage transforms the result set and passes it on to the next stage in the pipeline.

?pipeline=[{ stage1 },{ stage2 }, { stage3 }, ...]

In the below example, the pipeline contains two stages. The first is a $match stage. This filters the result set to all accounts create on or after 2015-01-01T00:00:00.000Z. Then that set of results is passed onto the $group stage which counts all of the accounts in the result set and finally returns a count result. For all available stages, see Pipeline Stages

GET /accounts?pipeline=[{"$match": {"created": {"$gte": "2015-01-01T00:00:00.000Z"}}}, {"$group": {"_id": null, "count": {"$count": "_id"}}}]
{
    "data": [
        {
            "count": 24
        }
    ],
    "hasMore": false,
    "object": "list"
}

Pipeline Stages

Name
Description
Example

A JSON object containing an _id property (required) and 0 or more property groupings.

{"$group": {"_id": null, "count": {"$count": "_id"}}}

An integer representing the number of results to return.

{"$limit": 100}

A JSON object containing operators and expressions used to limit the search results.

{"$match": {“$and”: [{“created”: {“$gt”: “2015-01-01T00:00:00.000Z”}}, {“created”: {“$lt”: “2015-06-01T00:00:00.000Z”}}]}}

A JSON object that specifies existing properties or new properties to pass along to the next stage in the pipeline.

{"$project",{"_id": 1, "name": 1}}

An integer representing the number of results to skip. Useful for paging where mapping or groupings have been applied, or where search the search criteria cannot be paged using unique fields.

{"$skip": 10}

A JSON object containing one or more properties, the values of which must be 1 for ascending and -1 for descending.

{"$sort": {"_id": -1}}

Accepts a property name and deconstructs an array into a single property in multiple documents.

{"$unwind": roles}

Result sets can be grouped in order to apply accumulators and aggregate data from accessible documents.

The $group stage takes the following form:

{"$group": {"_id": <expression>, <property>: { <accumulator1> : <expression> }, <property>: { <accumulator2> : <expression> },... }}

For available accumulators, see Accumulator Operators.

The _id property is your grouping expression and is required. The _id can be null, it can be a single property or a combination of properties and group expressions. When you specify an _id of null, you will group together all of the documents in the result set. This is helpful for calculating accumulated values for all of the documents, for example when calculating a cont of the total number of documents in your result. When the _id is null, it is not included in the result set.

Examples

In the following example, we aggregate a custom c_patient object with a two-stage pipeline. The first stage is a $match that filters the documents down to patients with a gender: 'f'. Those documents are then passed into the $group stage where we count all of the documents in the result set and return a count property. Because we pass null for the grouping _id, we can calculate an accumulation for the entire result set.

GET /c_patients?pipeline=[{"$match": {"gender": "f"}},{"$group": {"_id": null, "count": {"$count": "_id"}}}]
{
    "data": [
        {
            "count": 359
        }
    ],
    "hasMore": false,
    "object": "list"
}

The following example is a single-stage $group on the connections object. The grouping is by the connections' context._id. Then, a count is calculated for each context grouping and returned in total properties.

GET /connections?pipeline=[{"$group": {"_id": "context._id", "total": {"$count": "_id"}}}, {"$sort": {"total": 1}}]
{
    "data": [
        {
            "_id": "507f1f77bcf86cd799439011",
            "total": 2
        },
        {
            "_id": "55ff9db67a00a89c14aa31a6",
            "total": 4
        },
        {
            "_id": "4d656461626c6552756c656b",
            "total": 12
        },
        {
            "_id": "507f191e810c19729de860ea",
            "total": 52
        }
    ],
    "hasMore": false,
    "object": "list"
}

The limit stage limits the number of documents passed onto the next stage in the pipeline.

{"$limit": <integer>}

Examples

GET /c_patients?pipeline=[{"$match": {"c_gender": "f"}},{"$project": {"c_name": 1}},{"$limit":2}]
{
    "data": [
        {
            "_id": "59495fc1514ef1010000598d",
            "c_name": {
                "c_first": "Jane",
                "c_last": "Smith"
            }
        },
        {
            "_id": "59496035bfd25d0100661faf",
            "c_name": {
                "c_first": "Holly",
                "c_last": "Forrester"
            }
        }
    ],
    "hasMore": false,
    "object": "list"
}

The $match stage accepts a JSON document that specifies query conditions on indexed properties to filter the resulting document list. This document list is then passed onto the next stage of the pipeline or returned as the response if it is the last stage of the pipeline.

{"$match": {<query conditions>}}

See Query Operators for more details and examples of available conditions.

Examples

In this example, we have just a one stage pipeline where we match accounts by the first name in a custom script. This returns a result set of accounts filtered to only include Kevins.

GET /accounts?pipeline=[{"$match": {"name.last": {"$regex": "/^s/i"}}}]
{
    "data": [
        {
            "_id": "5888b91d35f8c91536c6ddea",
            "access": 6,
            "c_enrollments": [],
            "c_study_groups": [],
            "created": "2017-01-25T14:41:33.297Z",
            "email": "john@medable.com",
            "favorite": false,
            "gender": "m",
            "inherited_roles": [
                "000000000000000000000007",
                "000000000000000000000006"
            ],
            "key": {
                "fingerprint": "8e53d430-e30c-11e6-aaeb-99172490c13b",
                "secret": "heBcf2Wgh6hjezADTAc88wHJNGcJgwUd"
            },
            "locale": "en_US",
            "locked": false,
            "mobile": "+12223334449",
            "name": {
                "first": "John",
                "last": "Silver"
            },
            "object": "account",
            "roles": [
                "000000000000000000000004"
            ],
            "shared": false,
            "state": "verified",
            "updated": "2017-01-25T14:42:54.970Z",
            "updater": {
                "_id": "5888b91d35f8c91536c6ddea",
                "object": "account",
                "path": "/accounts/5888b91d35f8c91536c6ddea"
            }
        }
    ],
    "hasMore": false,
    "object": "list"
}
 

The projection stage takes a JSON document that can specify the inclusion of properties and/or the addition of new properties.

{"$project": {<projection spec>}}

Specifications

Specification
Description

property: 1 or true

Include this property in the projection

property: expression

Add a new property to the projection

Considerations

  • Except for _id, only properties that you specify for inclusion or add to the projection as new properties will be projected on to the next stage.
  • The _id property is always included in the projection, even if you don't specify inclusion.
  • Existing properties cannot be overridden in a projection. If you wish to transform an existing property in a projection, it is recommended that you instead add a new property with a different name.

Examples

In the below example, a custom c_patient object is aggregated with a two stage pipeline in a script. The first stage is a $match that finds all patient records with c_gender: 'm'. That result set is then passed into the $project stage. The projection then specifies that c_name, and c_gender properties are included and that fullName and age are added as new properties.

  • The new fullName property is a concatenation of the c_first and c_last sub-properties if the c_name document property using the $concat string operator and $string literal operator.
  • The new age property is calculated from an existing c_birthdate property, using $subtract, $divide, and $floor arithmetic operators to calculate the age from the difference between c_birthdate and today's date.
  • Since the $project stage is the last stage in the pipeline, the result of the projection is returned as the response.
return org.objects.c_patients.aggregate()
  .match({
  	c_gender: 'm'
	})
	.project({
  	c_name: 1,
  	fullName: {$concat: ['c_name.c_first', {$string: ' '}, 'c_name.c_last']},
    c_gender: 1,
    age: { $floor: { $divide: [{ $subtract:[new Date(), 'c_birthdate']}, (365 * 24*60*60*1000)]}}
	})
	.toList();
{
    "data": [
        {
            "_id": "59495fb2514ef1010000598b",
            "age": 38,
            "c_gender": "m",
            "c_name": {
                "c_first": "John",
                "c_last": "Smith"
            },
            "fullName": "John Smith"
        },
        {
            "_id": "59495fd7514ef1010000598f",
            "age": 48,
            "c_gender": "m",
            "c_name": {
                "c_first": "Charles",
                "c_last": "Jones"
            },
            "fullName": "Charles Jones"
        },
        {
            "_id": "59496012cfc40501006c10d2",
            "age": 43,
            "c_gender": "m",
            "c_name": {
                "c_first": "Richard",
                "c_last": "Roberts"
            },
            "fullName": "Richard Roberts"
        }
    ],
    "hasMore": false,
    "object": "list"
}

The skip stage skips over the specified number of documents and passes the remaining documents into the next stage of the pipeline.

{"$skip": <positive integer>}

Examples

GET /c_patients?pipeline=[{"$match": {"c_gender": "f"}},{"$project": {"c_name": 1}},{"$skip": 1},{"$limit":1}]
{
    "data": [
        {
            "_id": "59496035bfd25d0100661faf",
            "c_name": {
                "c_first": "Holly",
                "c_last": "Forrester"
            }
        }
    ],
    "hasMore": false,
    "object": "list"
}

The sort stage take all documents it receives and passes them into the next stage in the specified sort order.

{"$sort": {<property1>: <sort order>, <property2>: <sort order>, ...}}

Where sort order can be 1 for ascending or -1 for descending.

Performance Considerations

To optimize performance, it is best to use $sort at the beginning of the pipeline or near the beginning, after a $match and $limit. And $sort should always proceed $project, $unwind, or $group if it is required -- otherwise your query may be slow or time out.

Examples

GET /c_patients?pipeline=[{"$match": {"c_gender": "f"}},{"$limit": 2},{"$sort": {"c_name.c_last": 1},{"$project": {"c_name": 1}}}]
{
    "data": [
        {
            "_id": "59496035bfd25d0100661faf",
            "c_name": {
                "c_first": "Holly",
                "c_last": "Forrester"
            }
        },
        {
            "_id": "59495fc1514ef1010000598d",
            "c_name": {
                "c_first": "Jane",
                "c_last": "Smith"
            }
        }
    ],
    "hasMore": false,
    "object": "list"
}
 

Unwinding arrays and document arrays expands them into individual documents so that aggregation can take place of the resulting output. For example, mapping the roles array of an account with 3 roles results in 3 output documents, each containing a roles ObjectId property.

{"$unwind": <property>}
GET /accounts/?pipeline=[{"$project": {"roles": 1}}, {"$unwind": "roles"}]

{
    "data": [
        {
            "_id": "55ff9db67a00a89c14aa31a6",
            "object": "account",
            "roles": "000000000000000000000004"
        },
        {
            "_id": "55ff9db67a00a89c14aa31a6",
            "object": "account",
            "roles": "000000000000000000000005"
        },
        {
            "_id": "55ff9db67a00a89c14aa31a6",
            "object": "account",
            "roles": "000000000000000000000007"
        }
    ],
    "hasMore": false,
    "object": "list"
}
Suggest Edits

Aggregation Operators

 

Aggregation operators can be used to create expressions in the aggregation pipeline. The operators work like functions. They typically take either a single argument like this:

{[operator]: [argument]}

Or they take an array of arguments like this:

{[operator]: [[argument1], [argument2] ...]}

Aggregaton Operators Types

Type
Description

Boolean operators evaluate their expression and return a boolean result.

Comparison operators compare two arguments and return a boolean result or a number.

Arithmetic operators perform calculations on numbers and dates

String operators perform operations on string arguments.

Array operators perform operations on array arguments.

Set operators work on arrays but treats them as sets, ignoring duplicate entries and order and return a set as a result.

Literal operators return a value or expression without parsing or evaluating the expression.

Date operators perform operations on date arguments.

Conditional operators evaluate expressions and return a value depending on the result of the condition.

Accumulator operators take a single expression as input and evaluate that expression once for each document in the result set.

Suggest Edits

Boolean Operators

 
Operator
Description
Example

$and

Evaluates to true if all conditions in the passed in array evaluate to true.

{“$and”: [“c_active”, “c_fav”]}

$or

Evaluates to true if any condition in the passed in array evaluate to true.

{“$or”: [“c_active”, “c_fav”]}

$not

Evaluates to true if the property or expression evaluates to false.

{“$not”: “c_active”}

Suggest Edits

Comparison Operators

 
Operator
Description
Example

$cmp

Returns 0 if the two passed in array values are equivalent, 1 if the first value is greater than the second, -1 if the second value is greater than the first.

{“$cmp”: [“name.first”, {“$string”: “Jamie”}]}

$gt

Selects documents where the value of the property is greater than the passed in value.

{“c_bpm”: {“$gt”: 70}}

$gte

Selects documents where the value of the property is greater than or equal to the passed in value.

{“c_bpm”: {“$gte”: 70}}

$lt

Selects documents where the value of the property is lesser than the passed in value.

{“c_bpm”: {“$lt”: 70}}

$lte

Selects documents where the value of the property is lesser than or equal to the passed in value.

{“c_bpm”: {“$lte”: 70}}

$ne

Returns true if the first property or expression in the passed in not equivalent to the second.

{“$ne”: [“c_bpm”, {“$integer”: 100}]}

Suggest Edits

Arithmetic Operators

 
Operator
Description
Example

$trunc

Truncates a number down to an integer.

{ "$trunc": "c_value" } }

$sqrt

Takes the square root of an aggregated number.

{"$sqrt": {"$add": "c_value"}}

$ln

Takes the log of a number.

{"$ln": "c_number"}

$floor

Returns the largest integer less than or equal to the number

{"$floor": "c_number"}

$exp

Takes the e^n of a number

{"$exp": "c_number"}

$ceil

Returns the smallest integer greater than or equal to the specified number.

{"$ceil": "c_number"}

$abs

Takes the absolute value of a number.

{"$abs": "c_number"}

$add

Adds two or more array properties or expressions. In addition to numbers, a single Date value may be included in the array.

{“$add”: [“created”, “c_msOffset”]}

$multiply

Multiplies two or more number properties or expressions in the passed in array.

{“$multiply”: [“c_bpm”, “c_scalar”, {“$number”: 0.99}]}

$subtract

Subtracts the second element from the first in the passed in array. In addition to number properties, numbers and dates maybe be subtracted from a date value.

{“$subtract”: [“created”, “updated”]}

$divide

Divides the second element by the first in the passed in array.

{“$divide”: [“c_bpm”, {“$number”: 0.9}]}

$mod

Divides the second element by the first in the passed in array, and returns the remainder.

{“$divide”: [“c_bpm”, {“$number”: 20}]}

$pow

Raises the first number to the power of the second number.

{“$pow”: [“c_heartrate”, {“$number”: 2}]}

$log

Takes the log of the first number in the second number's base.

{“$log”: [100, 10] }
// result: 2

Suggest Edits

String Operators

 
Operator
Description
Example

$concat

Concatenates two or more string properties or expressions in the passed in array.

{“$concat”: [“name.first”, {“$string”: “ ”}, “name.last”]}

$substr

Returns a portion of a string. Takes an array of three elements: source string, integer start index and integer length. The integer values can be literals, properties, or expressions.

{“$substr”: [“c_desc”, 0, 20]}

$toLower

Returns a lowercase version of the string argument.

{“$toLower”: “c_title”}

$toUpper

Returns an uppercase version of the string argument.

{“$toUpper”: “c_title”}

$strcasecmp

Performs a case-insensitive string comparison. Returns 0 if the two passed in array values are equivalent, 1 if the first value is greater than the second, -1 if the second value is greater than the first.

{“$strcasecmp”: [“name.first”, {“$string”: “J”}]}

Suggest Edits

Array Operators

 
Operator
Description
Example

$size

Returns the size of the array argument. The argument must resolve to an array

{“$size”: “body”}

$slice

Returns the subset of an array.
Param 1: The master array
Param 2 (optional): the position to start evaluating the array from
Param 3: the number of elements from param 2 to return

{ $slice: [ [ 1, 5, 7, 9 ], 1, 2 ] }

// returns [5, 7]

$isArray

Returns true if the operand is an array

{"$isArray": [1,2,3]}
// returns true

$concatArrays

Returns an array which contains all the arrays concatenated together.

{"$concatArrays": [ [ "medable", "is"], [ "great" ] ] }

//returns ["medable", "is", "great"]

$arrayElemAt

Returns the element in the array at a specified index.

{ $arrayElemAt: [ [ "purple", "orange", "yellow" ], 1 ] }

//returns "orange"

Suggest Edits

Set Operators

 
Operator
Description
Example

$setEquals

Evaluates to true if the passed in array properties or expressions contain the same distinct elements

{“$setEquals”: [ {“$array”: [“cpg”, “mvc”, “kvm”]}, “c_requested” ] }}

$setIntersection

Returns the intersection between 2 or more input arrays.

{“$setIntersection”:[“c_available”, “c_reserved”]}

$setUnion

Combines 2 or more input arrays.

{“$setUnion”:[{“$array”: [“000000000000000000000007”]}, “roles”]}}}

$setDifference

Returns the difference between 2 or more input arrays.

{“$setDifference”:[{“$array”: [“000000000000000000000007”]}, “roles”]}}}

$setIsSubset

Returns true if the first array is a subset of the second.

{“$setIsSubset”: [“c_some”, “c_all”]}

$anyElementTrue

Returns true if any property or expression in the passed in array evaluates to true.

{“$anyElementTrue”: [“c_bool”, “c_fav”]}

$allElementsTrue

Returns true if all properties or expressions in the passed in array evaluate to true.

{“$allElementsTrue”: [“c_bool”, “c_fav”]}

Suggest Edits

Literal Operators

 
Operator
Description
Example

$literal

Allows the insertion of any literal value. This is used mainly when you'd like to use a value that would otherwise be evaluated as an expression.

pricesEqual: { $eq: [ "$cashValue", { $literal: "$10" } ] }

$string

Allows the insertion of a string literal. The value must be a string or an expression that evaluates to a string.

{“$concat”: [“c_pants”, {“$string”: “c_pants”}] } -> “clown c_pants”

$number

Allows the insertion of a number value as a literal where a property name would otherwise be expected. The value must be a number or an expression that evaluates to a number.

{“$add”: [“c_scalar”, {“$number”: 1.23}]}

$integer

Allows the insertion of an integer value as a literal where a property name would otherwise be expected. The value must be an integer or an expression that evaluates to an integer.

{“$add”: [“c_ints”, {“$integer”: 10}]}

$boolean

Allows the insertion of a boolean value as a literal where a property name would otherwise be expected. The value must be a boolean or an expression that evaluates to a boolean.

{“alwaysFirstName”: {“$first”: {“$cond”: [{“$boolean”: true}, “name.first”, “name.last”]}}}

$date

Allows the insertion of a date value as a literal where a property name would otherwise be expected. The value must be a date or an expression that evaluates to a date.

{“offsetDate”: {“$add”: [{“$date”: “2015-06-07T14:48:00.000Z”}, “c_offset”]}}

$objectId

Allows the insertion of an objectId value as a literal where a property name would otherwise be expected. The value must be an objectId or an expression that evaluates to an objectId.

{“$cmp”: [{“$objectId”: “561614700000000000000000”}, “_id”]}

$array

Allows the insertion of an array value as a literal where a property name would otherwise be expected. The value must be an array or an expression that evaluates to an array.

{“$setUnion”:[{“$array”: [“000000000000000000000007”]}, “roles”]}}}

$object

Allows the insertion of an object value as a literal where a property name would otherwise be expected. The value must be an object or an expression that evaluates to an object.

{“$eq”:
[ {“$object”: {
"street": "Easy St"
}}, “c_address”]}

Suggest Edits

Date Operators

 
Operator
Description
Example

$dayOfWeek

Returns the day of the week for the passed in date property or expression as a number from 1 (Sunday) to 7 (Saturday).

{"$dayOfWeek": "created"}

$dayOfMonth

Returns the day of the month for the passed in date property or expression as a number from 1 to 31

{"$dayOfMonth": "created"}

$dayOfYear

Returns the day of the year for the passed in date property or expression as a number from 1 to 366

{"$dayOfYear": "created"}

$year

Returns the year for the passed in date property or expression.

{"$year": "created"}

$month

Returns the month for the passed in date property or expression.

{"$month": "created"}

$week

Returns the week of the year for the passed in date property or expression as a number between 0 (the partial week that precedes the first Sunday of the year) and 53 (in a leap year).

{"$week": "created"}

$hour

Returns the hour for the passed in date property or expression as a number between 0 and 23.

{"$hour": "created"}

$minute

Returns the minute for the passed in date property or expression as a number between 0 and 59.

{"$minute": "created"}

$second

Returns the second for the passed in date property or expression as a number between 0 and 60 (for a leap second).

{"$second": "created"}

$millisecond

Returns the millisecond for the passed in date property or expression as a number between 0 and 999.

{"$millisecond": "created"}

$dateToString

Converts a date object to a string in a specified format, and expects an array of [<format>, date_expression]

{ "$dateToString": ["%Y-%m-%d", "created"] }

Date Format Specifiers

Specifiers
Description
Possible Values

%d

Day of Month (2 digits, zero padded)

01-31

%G

Year in ISO 8601 format

0000-9999

%H

Hour (2 digits, zero padded, 24-hour clock)

00-23

%j

Day of year (3 digits, zero padded)

001-366

%L

Millisecond (3 digits, zero padded)

000-999

%m

Month (2 digits, zero padded)

01-12

%M

Minute (2 digits, zero padded)

00-59

%S

Second (2 digits, zero padded)

00-60

%u

Day of week number in ISO 8601 format (1-Monday, 7-Sunday)

1-7

%U

Week of year (2 digits, zero padded)

00-53

%V

Week of Year in ISO 8601 format

1-53

%w

Day of week (1-Sunday, 7-Saturday)

1-7

%Y

Year (4 digits, zero padded)

0000-9999

%%

Percent Character as a Literal

%

Suggest Edits

Conditional Operators

 
Operator
Description
Example

$cond

Takes an array of 3 expressions. If the first expression evaluates to true, the second expression value is returned. Otherwise, the value of the third expression is returned.

{“$cond”: [“c_active”, {“$string”: “active”}, {“$string”: “inactive”}]}

$ifNull

Takes an array of 2 expressions. Returns the value of the first expression unless it evaluates to null, in which case the value of the second expression is returned.

{“$ifNull”: [“c_offset”, {“$integer”: 42}]}

Suggest Edits

Accumulator Operators

 
Operator
Description
Example

$count

Performs a count of a grouped documents or, if the property is an array, a count of the number of elements.

{“numInGroup”: {“$count”: “_id”}}

$sum

Calculates the sum of a number property or expression in the group.

{“sumOfDays”: {“$sum”: {“$dayOfMonth”: “created”}}}

$avg

Calculates the average of a number property or expression in the group.

{“averageHeartRate”: {“$avg”: “c_bpm”}}

$first

Returns the first value from the group. The result depends on the sort field(s).

{“oldest”: {“$first”: “created”}}

$last

Returns the last value from the group. The result depends on the sort field(s).

{“latest”: {“$last”: “created”}}

$min

Returns the smallest value from the group.

{“smallest”: {“$min”: “c_size”}}

$max

Returns the largest value from the group.

{“largestArray”: {“$max: {”$size": “c_arr”}}}

$pushAll

Returns the array of pushed values, with NULL included in the array where there are missing values

{"combinedArray": {"$pushAll": "c_value"}}

$push

Returns the array of pushed values

{"combinedArray": {"$push": "c_value"}}

$addToSet

Returns array of unique pushed values

{"uniqueArray": {"$addToSet": "c_value"}}

$stdDevPop

Returns the population standard deviation of input values

{"stdDeviation": { "$stdDevPop": "c_heartrate"}}

$stdDevSamp

Returns the sample standard deviation of input values

{"stdDeviation": { "$stdDevSamp": "c_heartrate"}}

Suggest Edits

Introduction

 

The Medable platform offers a JavaScript API for developers to create, read, update, and delete cortex objects; query and aggregate data; send custom notifications; perform callouts; console and debug logging; create object triggers; run scheduled jobs; create custom api routes and more.

All scripts run synchronously. There are no callbacks or timers and as such no implementation of functions such as setInterval, setTimeout or setImmediate. For example, a route script employing an http callout might look like the following:

import http from 'http';

try {
  const response = http.get('https://www.example.com/service?json');
  return JSON.parse(response.body);  
} catch(err) {
    // handle me
}
Suggest Edits

Environment Notes

 

The Javascript engine is ECMAScript 5/5.1 compliant. You can also use many ES2015 features and some decorators. The following babel plugins are enabled:

babel-plugin-check-es2015-constants
babel-plugin-transform-decorators-legacy
babel-plugin-transform-class-properties
babel-plugin-transform-regenerator
babel-plugin-transform-es2015-arrow-functions
babel-plugin-transform-es2015-block-scoped-functions
babel-plugin-transform-es2015-block-scoping
babel-plugin-transform-es2015-classes
babel-plugin-transform-es2015-computed-properties
babel-plugin-transform-es2015-duplicate-keys
babel-plugin-transform-es2015-function-name
babel-plugin-transform-es2015-literals
babel-plugin-transform-es2015-modules-commonjs
babel-plugin-transform-es2015-object-super
babel-plugin-transform-es2015-parameters
babel-plugin-transform-es2015-shorthand-properties
babel-plugin-transform-es2015-spread
babel-plugin-transform-es2015-template-literals
babel-plugin-transform-es2015-destructuring
babel-plugin-transform-es2015-for-of
babel-plugin-transform-es2015-typeof-symbol
babel-plugin-transform-object-rest-spread

The following decorators are built-in and can be imported using the decorators-{decoratorName} convention: autobind, decorate, deprecate, enumerable, extendDescriptor, lazyInitialize, nonconfigurable, nonenumerable, override, readonly.

import autobind from 'decorators-autobind';
import readonly from 'decorators-readonly';

class Eye {   
    
    @readonly
    pie = 'pie'; // initializable properties support.

    @autobind
    apple() {
        return this.pie;
    }
    
    orange = () => this.pie; // bound functions support.
}

const eye = new Eye();

eye.apple.call(null); // 'pie' returned even though bound to null.
eye.orange.call(null); // 'pie' returned even though bound to null.
eye.pie = 'not allowed'; // throws 

Module loading is available via CommonJS; Standard and custom modules are loaded using require and defined using module.exports. Imports and exports are also supported.

For example, a module exported as c_utils, defined as:

import _  from 'underscore';

export default {
  
  dateToAge: function(birthDate) {
    if (!_.isDate(birthDate)) return 0;
    
    const today = new Date(),
          m = today.getMonth() - birthDate.getMonth();
    
    let age = today.getFullYear() - birthDate.getFullYear();
    
    if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
      age--;
    }
    return age;
  }
};

might be loaded and used in a route as follows:

import utils from 'c_utils';

const me = org.objects.Accounts
  .find({
    _id: script.principal._id
  })
  .paths('dob')
  .next();

return utils.dateToAge(new Date(me.dob));

All scripts run in strict mode. For triggers, jobs and routes the entry point to the script is called main, which can be seen in script stack traces. In order to get meaningful stack traces, it's good practice to name all functions.

Stack traces are available for debugging via the Error object's trace property or the getCurrentStackTrace global function. A stack trace is also provided with calls to the logger or console modules.

The console, consts, org and script auto-globals are always guaranteed to be available, though console printing only works on the development servers.

Suggest Edits

Script Types

 
 
// Example of a custom time-based access control mechanism in an account trigger update.
var hour = new Date().getUTCHours();
if (!(hour >= 8 && hour <= 17)) {
    throw new Error('Updates are only allowed between 8am and 5pm GMT');
}

// Update the c_random property each time the instance is updated (not directly writable by the account holder).
script.arguments.new.update('c_random', Math.random(), {grant: 8});

Triggers can be setup to run before and/or after creation, update, and deletion of object instances, as well as before and after session authentications (to allow for custom authentication mechanisms).

All before triggers are run inline, that is they return false or throw an error from the script to cancel the operation. In object instance before triggers, changes can be made inline to instance properties directly from the script, and made as either the script's calling principal or given a grant. These changes are recorded in the audit logs as separate events.

All before update trigger code should be idempotent, as they may run more than once during update conflict resolution events.

An after script runs after the operation that triggered it has completed and is ideally suited for sending notifications. These triggers are guaranteed to run only once.

// example of utilizing a path parameter to output an xml-document.
// This route was configured as GET /routes/multiply/:a/:b

var req = require('request'),
    res = require('response'),
    xml = require('xml');

var response = {
    total: req.params.a * req.params.b
};

res.setHeader('Content-Type', 'text/xml');
res.write( xml.toXml(response) );

A route script creates new API endpoints for an organization. Route matching is available using wildcards, named-parameters and regular expression matching. A route can be set to run as the calling principal or as any other available org principal. ACL can also be applied at the configuration level in order to restrict endpoint access to a set of roles or specific accounts.

PUT and POST routes can be configured to parse application/x-www-form-urlencoded form data, as well as accept text/ content-types. When accepting text/ content, the request body will be in raw form. Otherwise, application/json and application/x-www-form-urlencoded are parsed into json objects.

import notifications from 'notifications';
import moment from 'moment';

// load administrators.
const adminIds = org.objects.accounts
  .find({roles: '000000000000000000000004'})
  .paths('_id')
  .skipAcl(true)
  .grant(4)
  .map(doc => doc._id);

// set desired time periods.
const startDate = moment(new Date()).utc().subtract(1,'day').startOf('day').toDate(),
      endDate = moment(new Date()).utc().subtract(1,'day').endOf('day').toDate();

// aggregate counts.
const cursor = org.objects.c_widgets.aggregate()
  .match({created: {$gte: startDate, $lte: endDate}})
  .group({_id: null, count: {$count: '_id'}});
   
const count = cursor.hasNext() ? cursor.next().count : 0;

// create report.
const report = {
  c_num_new_widgets: count
};

// send notification to admins.
adminIds.forEach(_id => 
  notifications.send('c_daily_report', report, {recipient: _id})
);

Jobs are scheduled using standard cron syntax and are suited for maintenance tasks, statistics gathering and data post-processing.

Suggest Edits

Libraries

 

A library is a CommonJS library that can be loaded by triggers, jos, routes, and other library scripts. The format follows that of a common js module. A library is configured with an export property, the name that will be used to import into other scripts. The name follows the same c_ naming convention as the rest of the api.

module.exports = {
    foo: function() {
        return 'bar';
    }
}
function Thing() {
}
Thing.prototype.foo = 'bar';

module.exports.Thing = Thing;
 

An ObjectID class is available to scripts in order to facilitate working with BSON object ids used to represent unique identifiers.

ObjectId(string/date/number)
Takes a hex string representation of an object id, a date or a timestamp in milliseconds.

id.toString()
returns the BSON id as a hexstring

id.toJSON()
Used primarily by JSON.stringify(), returns the BSON id as a hexstring.

id.equals(other)
Returns true if the passed in argument contains the same value as the id. The argument may be a hexstring or an ObjectID instance.

id.toDate()
Returns the time the ObjectID was create as a Date value.

id.getTimestamp()
Returns the number of seconds between midnight of January 1, 1970 and the time the ObjectID was created.

return {
    date: new ObjectID(new Date()),
    dateDate: new ObjectID(new Date()).toDate(),
    id: new ObjectID(),
    idDate: new ObjectID().toDate(),
    str: new ObjectID("4a232bca18759fcbdef24855"),
    strDate: new ObjectID("4a232bca18759fcbdef24855").toDate(),
    ts: new ObjectID("4a232bca18759fcbdef24855").getTimestamp()
}
{
    "date": "56d615040000000000000000",
    "dateDate": "2016-03-01T22:17:40.000Z",
    "id": "56d615048cacf5d0013e9305",
    "idDate": "2016-03-01T22:17:40.000Z",
    "str": "4a232bca18759fcbdef24855",
    "strDate": "2009-06-01T01:15:54.000Z",
    "ts": 1243818954
}
Suggest Edits

CortexObject

 

The class that represents built-in/custom object definitions and represents the upcoming standard for cursor-based instance access within the Cortex scripting environment.

script.principal and script.context (when it exists) are CortexObject instances. This makes the following valid code:

  • script.principal.update('name.first', 'Tim') (update the name of the current principal)
  • script.context.cancel('not a good time') (deployment.before script)

org auto-global, the accounts and view modules extend CortexObject. This makes the following true:

  • require('accounts') === org.objects.accounts
  • script.org === org
  • typeof require('views').find === 'function'
  • typeof org.objects.accounts.createAuthToken === 'function'

Obtaining an instance cursor is as easy as org.objects.c_custom.find().

CortexObject can be easily extended in order to provide custom functionality to all your objects through as() or simply by extending it directly.


// new base custom object -------

class CustomBase extends CortexObject {
    static findOne(filter, ...paths) {
        const cursor = this.find(filter).skipAcl().limit(1).grant(8);
        if (paths.length) {
            cursor.paths(...paths);
        }
        return cursor.hasNext() ? cursor.next() : null;
    }
};
CustomBase.as('c_my_object').findOne();

const obj = CustomBase.as('Account').findOne({email: 'chazz@reinhold.com'}, 'name');

// or we can just name the class -------

class c_My_Object extends CortexObject {

   static findAllFoos(skip = 0, limit = 100) {
        return this.find({c_foo: true}).skip(skip).limit(limit).toList()          
    }
}
return c_My_Object.findAllFoos();

Static Methods

as(objectName) Extend CortexObject
from(context) Create CortexObject instance from document
aggregate(pipeline=[]) Start an aggregation operation
count(match) Count matching documents
deleteOne(match) Start a delete operation
find(match) Start a query operation
insertOne(doc) Start an insert operation
setOwner(id, to) Transfers ownership to another account
updateOne(match, doc) Start an update operation

as(objectName)

Extends CortexObject and returns a class with a constructor name matching objectName.

Arguments

  • objectName (String)

Returns

Class

const Nums = CortexObject.as('c_num');
const _id = Nums.insertOne({c_val: [1, 2, 3]}).execute();

from(context)

Returns an instance of a CortexObject based on the passed in context argument, which should have at least _id and object properties.

Arguments

  • context (Object)

Returns

CortexObject instance

aggregate(pipeline=[])

Returns an aggregation cursor based on the optional passed in pipeline argument. The pipeline must be in the form of an array and named aggregation steps ([{$match: {...}}, {$project: {...}}, ...]). A pipeline can also be built later using aggregation cursor chaining.

Arguments

  • pipeline (Object[])

Returns

AggregationCursor

count(match)

Returns a count of matching documents of the current CortexObject.

Arguments

  • match (Object) Optional match filter document.

Returns

Number

deleteOne(match)

Returns a delete operation based on the passed in match filter.

Arguments

  • match (Object) Optional match filter document.

Returns

(DeleteOperation)

find(match)

Returns a cursor based on the passed in match filter.

Arguments

  • match (Object) Match filter document.

Returns

QueryCursor

insertOne(doc)

Returns an insert operation.

Arguments

  • doc (Object) The document to insert.

Returns

InsertOperation

setOwner(id, to)

Transfers ownership of a context object to another account.

Arguments

  • id (ObjectID) The identifier of the instance to update.
  • to (ObjectID|String) The identifier or email of the new owner account.

Returns

Boolean true is modified or false if already owned by to.

Warning

setOwner is a low-level operation and does not implement any access controls, though an Audit log record is produced.

updateOne(match, doc)

Returns an update operation based on the passed in match filter.

$set and $push operations support updating existing document array elements by including their identifiers (e.g. push 2 items into c_arr of a specific document in the c_docs document array: { $push: {c_docs: {_id: '599284e01c9e955ff7526793', c_arr: [1, 2] }}}).

$unset operations can remove properties buried in specific documents

Arguments

  • match (Object) Optional match filter document.
  • doc (Object) An object containing the changes to effect. Update supports $set, $push, $unset and $remove.
    • $set Contains properties to update. (e.g. {$set: {name: {first: 'Auric', last: 'Goldfinger'}}})
    • $push Contains items to push into arrays and document arrays (e.g. {$push: {c_names: ['Jill Masterson']}})
    • $unset Unset one or more deletable properties (e.g. {$unset: {'c_doc.59928b74341a65ef3f03842b.c_deletable': 1, c_remove_me: 1}}).
    • $remove Removes elements from arrays, by full path (e.g. remove 2 documents from c_doc_array by identifier and all 1 and 2 values from c_num_arr in the c_doc_array document with an identifier of 59928b74341a65ef3f03842b: $remove: {'c_doc_array': ['59928aed341a65ef3f03836a', '59928af9341a65ef3f038380'], 'c_doc_array.59928b74341a65ef3f03842b.c_num_arr': [1,2] })

Returns

UpdateOperation

const Nums = CortexObject.as('c_nums');

Nums.updateOne({_id: '5992879ef4e03e6c3f682c5e'}, {
  $push: {    
    c_doc: {
      c_arr: [1, 2, 3]
    }
  },
  $set: {
    c_doc: [{
      _id: '59928b74341a65ef3f03842b',
      c_del: 420,
      c_arr: [1, 2, 3, 4]
    }]
  },
  $unset: {
    'c_doc.59928b74341a65ef3f03842b.c_del': 1
  }, 
  $remove: {
    c_doc: ['59928aed341a65ef3f03836a', '59928af9341a65ef3f038380']
    'c_doc.59928b74341a65ef3f03842b.c_arr': [1,2]
  }
}).execute();
Suggest Edits

Accounts

Adds custom account registration, authentication, and verification.

 
const Accounts = org.objects.accounts;
// or import Accounts from 'accounts'; 

// find first readable account.
Accounts.find().paths('email').next().email; 

// script principal is an Account instance.
script.principal.update('name.first', 'Myself'); 

Methods

failAuth()
login(payload, options)
preAuth(email)
register(payload, options)
provision(payload, options)
createAuthToken(apiKey, subject, options)
decodeAuthToken(token)
authorizeToken(token)
revokeAuthToken(tokenOrId)
getSubjectTokens(apiKey, subject)
revokeSubjectTokens(apiKey, subject)
inAuthScope(compiledScope, scopeString, matchPrefix)

failAuth()

Record an audit record failed authentication attempt in the logs. Developers should call this after a custom authentication failure. This will increment the auth attempts counter and lock the account if required. Always throws either kInvalidCredentials or kAccountLocked.

Additionally, an account locked notification is sent to the account holder if the account is locked.

Arguments

  • email (String) The account login email address.

login(payload, options)

Enables account login through a script. Use in conjunction with preAuth and failAuth to use the built-in authentication failure lock-out mechanism.

Arguments

  • payload (Object) Uses the same options as the Login endpoint. Though password may be omitted if the passwordLess options is set.
  • options (Object)
    • passwordLess (Bool) If true, skips password check.
    • verifyLocation (Bool) Defaults to true. When false, 2fa based on location md.fingerprint is completely ignored. Useful for SSO scenarios where 2fa would presumably be handled by the identify provider.

Returns

principal (Object)

  • _id (ObjectId) The identifier of the principal who called the script
  • email (String) The principal's email address
  • name (Object)
    • first (String) The principal's first name
    • last (String) The principal's last name
  • roles (ObjectId[]) A list of the principal's assigned org roles

Note

accounts.login() is only available in Route scripts.

preAuth(email)

Checks to ensure the account exists and is not locked. throws kInvalidCredentials or kAccountLocked.

Arguments

  • email (String) The account login email address.

Returns

  • account (Account) The Account object as read by the account itself.

register(payload, options)

Enables account provisioning through a script, bypassing the org's self-registration setting.

This version requires that a request be present and must be called from a route.

Arguments

  • payload (Object) Uses the same options as the Registration endpoint.
  • options (Object)
    • skipVerification (Bool) Set new account state to 'verified'. Normally, initial account state is 'unverified' and an account is verified through an email link that includes a verification token. Unverified accounts cannot create connections or be connection targets.
    • skipActivation (Bool) Skip activation when an org is configured to require activation prior to login.
    • skipNotification (Bool) Suppress provisioned account password reset welcome email for newly provisioned accounts.
    • requireMobile (Bool) Defaults to true. If false, an account can be created without a mobile number.
    • requireMobile (Bool) Defaults to true. If false, an account can be created without a mobile number.
    • verifyLocation (Bool) When provisioning an account whose caller is the target of the account creation, the md.fingerprint cookie will be created and the current location verified automatically.

Returns

  • account (Account) The account object as read by the newly registered account holder.

provision(payload, options)

Offline account provisioning.

Arguments

  • payload (Object) Uses the same options as the Registration endpoint.
  • options (Object)
    • skipActivation (Bool) Skip activation when an org is configured to require activation prior to login.
    • sendWelcomeEmail (Bool) Set to false to suppress provisioned account password reset welcome email.

Returns

  • account (Account) The account object as read by the newly registered account holder.

createAuthToken(apiKey, subject, options)

See Token Authentication and Scoping for more information about scopes and jwt claims.

Creates a JWT access token used for scoped access the api.

Arguments

  • apiKey (String) The api key of the issuing application. Generate API Key
  • subject (String|ObjectID) The account identifier or email address for which the token is issued. Using the token will authenticate the caller as the subject.
  • options (Object)
    • activatesIn (Number) Optional number of seconds until the token activates. Incompatible with validAt, and expiresIn must exist to use this option.
    • validAt (Date) The date when the token activates. Incompatible with activatesIn, and expiresIn must exist to use this option.
    • expiresIn (Number) Optional number of seconds the token will be active, between 1 and the app's authDuration setting (typically 900). Incompatible with permanent, and defaults to authDuration.
    • grant (Number) Increases the grant level for all operations. Use with extreme care.
    • maxUses (Number) Limits the number of times the token can be authorized. Sets the 'jti' claim, so limited-use tokens can be revoked.
    • permanent (Bool) If true, creates an auth token that can be used forever and can be revoked by token id or by regenerating the app's RSA key pair. Incompatible with expiresIn.
    • roles (ObjectID[]) Additional roles granted to the token subject at runtime.
    • scope (String[]) Scopes to which the token is limited. If no scopes are passed, [] is assumed, which renders the token next to useless unless there are scoped roles.
    • skipAcl (Bool) Set to true to bypass Object defaultAcl for matching objects. A grant is still required to allow property access. Use with extreme care.
    • bypassCreateAcl (Bool) Set to true to bypass an Object createAcl. Use with extreme care.

decodeAuthToken(token)

Decodes an auth token into a human-readable JSON document.

Arguments

  • token (String) The JWT access token.

Returns
token (Object) The decoded JWT access token

{
  "aud": "https://api.dev.medable.com/example/v2",
  "cortex/gnt": 4,
  "cortex/scp": [
    "object.read.account.58ffcf06f0d11f3788826fcf.name",
    "object.read.c_messages.*.c_subject"
  ],
  "cortex/skp": true,
  "exp": 1498674945,
  "iat": 1498674045,
  "iss": "H2gFRtKGyLKvSEdOf5aYpf",
  "sub": "58ffcf06f0d11f3788826fcf"
}

authorizeToken(token)

Authorizes an access token and returns the resulting account principal. Typically, calls into the api are already authenticated (using the Authorization request header). This method exists mainly for developer use in debugging token authentication and scoping.

Arguments

  • token (String) The JWT access token.

Returns
principal (Object)

revokeAuthToken(tokenOrId)

Revoke a permanent or limited-use auth token by token or jti. Only tokens creates using the permanent or maxUses options can be revoked.

Arguments

  • tokenOrId (String|ObjectID) The JWT access token or jti claim value.

Returns
revoked (Bool) True is revoked, false if the token does not exist.

getSubjectTokens(apiKey, subject)

Retrieves details of active permanent and limited-use auth tokens for a subject.

Arguments

  • apiKey (String) The api key of the issuing application.
  • subject (String|ObjectID) The account identifier or email address for which the token was issued.

Returns
details[] (Object[])

  • jti (String) The unique token identifier
  • last_accessed (Date) The date the token was last authorized (does not exist until the first access)
  • times_accessed (Number) The number of times the token was authorized (does not exist for limited-use tokens)
  • uses_remaining (Number) The remaining number of times the token can be authorized
[
  {
    "_id": "59486e7f53c603e8688cb5f7",
    "last_authorized": "2017-06-28T17:10:26.249Z",
    "times_authorized": 304
  },
  {
    "_id": "5953ebc9749219f1a2eedc57",
    "times_authorized": 0
  },
  {
    "_id": "595415684cffa322569c4820",
    "expires_at": "2017-06-28T21:00:28.000Z",
    "uses_remaining": 3
  }
]

revokeSubjectTokens(apiKey, subject)

Revokes all permanent or limited-use tokens for a subject.

Arguments

  • apiKey (String) The api key of the issuing application.
  • subject (String|ObjectID) The account identifier or email address for which the token was issued.

Returns
revoked (Number) The count of revoked tokens.

inAuthScope(compiledScope, scopeString, matchPrefix)

Checks if a scope string is within the purview of a compiled scope.

Arguments

  • compiledScope (Object[]) The compiled principal scope. Can be retrieved through script.principal.scope or org.objects.accounts.authorizeToken(token).scope.
  • scopeString (String) The scope string to check (eg. object.read.c_messages).
  • matchPrefix (String) Defaults to true. If false, requires an exact match all the way down the chain. For example, object.read.c_messages will not match a compiled scope with object.read.c_messages.*.c_subject when false.

Returns
in_scope (Boolean) True if the scopeString is within the compiled scope.

Examples

Creating and testing auth scope.

require('should');

const token =  org.objects.account.createAuthToken(
  'H2gFRtKGyLKvSEdOf5aYpf',
  'james@medable.com',
  {
    scope: [      
      "object.read.c_messages.*.c_subject"
    ]    
  }
)

const principal = org.objects.account.authorizeToken(token);

org.objects.account.inAuthScope(principal.scope, 'object.read.c_messages', true).should.equal(true);

org.objects.account.inAuthScope(principal.scope, 'object.read.c_messages', false).should.equal(false);

Custom registration: Here we have an example custom registration script. It takes a request body that contains the necessary properties to register an account, registers that account, logs that user in, and returns the account object.

import accounts from 'accounts';
import request from 'request';

/* example request body
{
  email: 'GordonDownie@TheTragicallyHip.com',
  name: {
      first: 'Gordon',
      last: 'Downie'
  },
  mobile: '+15555555555',
  password: 'new orleans is sinking, man, and i don\'t wanna swim',
  roles:[customRoleId]
}
*/

const options = {
    skipVerification: true,
    skipActivation: true,
    skipNotification: true,
    verifyLocation: true
};

let account = accounts.register(request.body, options);

// verifyLocation ensures the caller is logged in without a kNewLocation fault.
let principal = accounts.login({
    email: account.email
}, {
    passwordLess: true
});

return account;

Custom authentication: Here we have a custom authentication script that checks with a third-party authentication system, and if successful authenticates the user. This type of custom authentication can be useful for single sign-on use cases or where user identity is managed via an external provider.

import req from 'request';
import accounts from 'accounts';
import http from 'http';

const payload = {
    email: req.body.email
};

// this checks for account existence and lock. should be called prior to custom authentication.
let account = accounts.preAuth(req.body.email);

// custom authentication here (token is some sort of 3rd party auth token).
let response = http.post('https://my.login.com/auth_me', {token: req.body.token});

// if authentication fails, increment attempts, fail and throw.
if (response.body.err) {
    accounts.failAuth(req.body.email, response.body.err);
}

// was there a 2fa location verification code attached?
if (req.body.code) {
    payload.location = {
        verificationToken: req.body.code
    };
}

// login without a password. note that the account 'clientKey' cannot be attached when no password is used.
return accounts.login(payload, {
    passwordLess: true
});
const Views = org.objects.views;
// import Views from 'views';
// const Views = CortexObject.as('views');

Methods

run(name, options)
passthru(name, options)

run(name, options)

Run a stored View.

Arguments

  • name (String) the view name
  • options
    • where
    • map
    • group
    • sort
    • paths
    • limit
    • skip
    • pipeline

Returns

Object[]

passthru(name, options)

Runs a stored View and returns a cursor (without fetching any results) which can be returned from a route script and streamed directly through the api. See QueryCursor.passthru()

Arguments

  • name (String) the view name
  • options
    • where
    • map
    • group
    • sort
    • paths
    • limit
    • skip
    • pipeline

Returns

Cursor

 
Suggest Edits

QueryCursor

 
return org.objects.account
  .find()
  .skipAcl()
  .grant(consts.accessLevels.read)
  .paths('_id', 'name.first')
  .sort({'name.first': 1})
  .limit(50)
  .toList() // use paging with hasMore

QueryCursor.access(level)

Sets the minimum context access level the caller needs to return results. To return only results to which the caller has update access, for example, call cursor.access(consts.accessLevels.update).

Arguments

  • level (Number)

Returns

this

QueryCursor.batchSize(sz)

Sets the internal cursor batch size for fetching results. Normally, the default is optimal but in cases where a large number of very small documents is being fetched, a larger batch size may be slightly more performant.

Arguments

  • sz (Number) The internal cursor batch size (between 1 and 1000).

Returns

this

QueryCursor.close()

Releases the cursor resources. It's not necessary to close cursors as this is done automatically when a script ends or is exhausted, but in some cases a script may need to free up a cursor mid-stream in order to open up another one.

Returns

this

QueryCursor.count()

Executes a count using the current match filter and cursor options.

Returns

Number the number of matched documents.

QueryCursor.expand(...props)

Sets the references that should be expanded in the returned documents. Reference properties can also be selectively retrieved using the paths option.

Arguments

  • ...props (String) Property paths to expand.

Returns

this

QueryCursor.forEach(fn)

Executes the cursor, calling fn with each document.

Arguments

  • fn (Function) a function to call for each element in the form of (document) => {}.

Returns

undefined

QueryCursor.grant(level = null)

Sets the property grant level for the operation.

Arguments

  • level (Number)

Returns

this

QueryCursor.hasNext()

Executes the cursor, returning true if next() can be safely called to fetch the next result.

Returns

bool

QueryCursor.include(...props)

Sets the optional properties to include in results. Optional properties can also be explicitly retrieved using the paths option. Some properties are marked as optional, meaning they are not included in results by default (e.g. certain List properties).

Arguments

  • ...props (String) Property paths to include (e.g. include('connections'));

Returns

this

QueryCursor.isClosed()

Returns true if a cursor has been opened and has been subsequently closed or exhausted.

Returns

Boolean

QueryCursor.limit(count)

Limits the number of query results to count. By default, the script toList() limit is 10, though cursors have no default limit.

Arguments

  • count (Number) The limit.

Returns

this

QueryCursor.map(fn)

Exhausts the cursor, calling fn with each document, and returning an array of results. Because map() iterates through the cursor, the caller should set a sane limit().

Arguments

  • fn (Function) a function to call for each result in the form of (document) => { return document; }.

Returns

Object[]

QueryCursor.maxTimeMs(ms)

Set the maximum time a query is allowed to run.

Arguments

  • ms (Number) A number between 10 and 10000.

Returns

this

QueryCursor.next()

Returns the next result. Throws a RangeError is there are no more results. Use while ( cursor.hasNext() ) { cursor.next() } or for result of cursor loops to iterate cursors.

Returns

Object

QueryCursor.passthru()

Opens a cursor (without fetching any results) which can be returned from a route script and streamed directly through the api. When returned, the script is detached and the cursor remains open until it's exhausted, incurring no further script ops or serialization costs. This is ideal for returning query results that do not require any post-query in-script processing.

- Without passthru: return org.objects.c_example.find().toList() (script->api->script->api->response)
- With passthru: return org.objects.c_example.find().limit(10).passthru() (script->api->response)

Returns

Object

QueryCursor.pathPrefix(path = null)

Sets the query prefix for retrieving a nested List property. All cursor options are passed through the path down to the list (including grant and skipAcl). Compatible with next(), toArray(), and with passthru() (to retrieve a streamable cursor). For example, org.objects.c_grandparent.find().pathPrefix( '5a2c44bc8664e438e45387d5.c_parents.5a2c44f88664e438e45387d6.c_children' ).where( {c_prop: value} ) passes the where() option down through 2 list properties to the c_parents.c_children.

Arguments

  • path (String) Path to a list property.

Returns

Object

QueryCursor.pathRead(path, options)

Returns the first matching document single path base on the current cursor options.

Arguments

  • path (String) Property path to read (Reading through references and lists is supported. eg "/creator/name/first").
  • options (Object)
    • throwNotFound (Boolean) Defaults to true. If false, will return null if no match is found.

Returns

Object

QueryCursor.paths(...props)

Limits the result properties to ...props. Only properties specified here (and those include()/expand()) are included in the results. Expandable reference properties and optional properties can also be listed here instead, limiting the output of those properties. For example, cursor.paths('c_parent.owner.name') jumps through the c_parent reference and it's owner reference to return the name property. Path lookups through references requires appropriate access permissions.

Arguments

  • ...props (String) Property paths to return in results.

Returns

this

QueryCursor.reduce(fn, memo)

Exhausts the cursor, calling fn with memo for each document, and returning memo. Because reduce() iterates through the cursor, the caller should set a sane limit().

Arguments

  • fn (Function) a function to call for each result in the form of (memo, document) => { return memo; }.
  • memo (Object) an initial value for fn.

Returns

Object

QueryCursor.skip(count)

Skips count number of results. Please not that large offsets can be expensive and slow down your query. It's more efficient to use range queries.

Arguments

  • count (Number) The number of results to skip.

Returns

this

QueryCursor.skipAcl(bool = true)

Skips initial lookup access control checks. Use in conjunction with grant() to set property level access.

Arguments

  • bool (Boolean)

Returns

this

QueryCursor.sort(object)

Sets the sort options (e.g. {c_num_prescriptions: -1, c_fullname: 1});

Arguments

  • sort (Object) an object containing indexed, sortable properties to sort on and their direction (1, -1)

Returns

this

QueryCursor.stream(fnEach, fnMap)

Exhausts the cursor, setting the content type to application/json and writing directly to the Response as a list object. Values returned from the script after stream is called are ignored.

Arguments

  • fnEach (Function) optional function - (result, total) => { return false; } - called after each item is written. Returning false ends the stream early.
  • fnMap (Function) optional function - (result) => { return result; } - called to transform each result before output, the result of which is JSON.stringify()'d.

Returns

undefined

QueryCursor.where(filter)

Overwrites the initial filter passed in the constructor.

Arguments

  • filter (Object)

Returns

this

const skip = require('request').params.skip;

const cursor = org.objects.c_nums
  .find()
  .paths('_id')
  .skipAcl()
  .skip(skip)
  .grant(1)
  .limit(10000)

return cursor.passthru();

QueryCursor.toArray()

Exhausts the cursor and returns an array of results (not a list! see toList() ). Because toArray() iterates through the cursor, the caller should set a sane limit().

Returns

Object[]

QueryCursor.toList()

Returns a list object based on limit() (or the default limit of 10).

Returns

List ({object: 'list', data: [...], hasMore: true})

QueryCursor.wrap(bool = true)

Where applicable, returns results as CortexObject instances instead of plain Javascript objects.

Arguments

  • bool (Boolean)

Returns

this

Suggest Edits

AggregationCursor

 
const cursor = org.objects.account
  .aggregate()
  .skipAcl()
  .grant(consts.accessLevels.read)
  .sort({
    'name.first': 1
  })
  .project({
    _id: 1,
    'name.first': 1
  })
  .limit(50);

const first_names = []; 
for (let account of cursor) {
  first_names.push( account.name.first );
}
return first_names;

// OR return cursor.map(v => v.name.first)
const cursor = org.objects.account
  .aggregate()
  .skipAcl() 
  .grant(consts.accessLevels.read)
  .sort({
    'name.first': 1
  })
  .project({
    _id: 1,
    first_name: 'name.first'
  })
  .limit(50)
  .stream(); // stream json directly to the response object.

AggregationCursor.access(level)

Sets the minimum context access level the caller needs to return results. To return only results to which the caller has update access, for example, call cursor.access(consts.accessLevels.update).

Arguments

  • level (Number)

Returns

this

AggregationCursor.batchSize(sz)

Sets the internal cursor batch size for fetching results. Normally, the default is optimal but in cases where a large number of very small documents is being fetched, a larger batch size may be slightly more performant.

Arguments

  • sz (Number) The internal cursor batch size (between 1 and 1000).

Returns

this

AggregationCursor.close()

Releases the cursor resources. It's not necessary to close cursors as this is done automatically when a script ends or is exhausted, but in some cases a script may need to free up a cursor mid-stream in order to open up another one.

Returns

this

AggregationCursor.forEach(fn)

Executes the cursor, calling fn with each document.

Arguments

  • fn (Function) a function to call for each element in the form of (document) => {}.

Returns

undefined

AggregationCursor.grant(level = null)

Sets the property grant level for the operation.

Arguments

  • level (Number)

Returns

this

AggregationCursor.group(object)

Adds a $group stage to the aggregation.

Arguments

  • object (Object)

Returns

this

AggregationCursor.hasNext()

Executes the cursor, returning true if next() can be safely called to fetch the next result.

Returns

bool

AggregationCursor.isClosed()

Returns true if a cursor has been opened and has been subsequently closed or exhausted.

Returns

Boolean

AggregationCursor.limit(count)

Adds a $limit stage to the aggregation. By default, the script toList() limit is 10, though cursors have no default limit.

Arguments

  • count (Number)

Returns

this

AggregationCursor.map(fn)

Exhausts the cursor, calling fn with each document, and returning an array of results. Because map() iterates through the cursor, the caller should set a sane limit().

Arguments

  • fn (Function) a function to call for each result in the form of (document) => { return document; }.

Returns

Object[]

AggregationCursor.match(object)

Adds a $match stage to the aggregation.

Arguments

  • object (Object)

Returns

this

AggregationCursor.maxTimeMs(ms)

Set the maximum time a query is allowed to run.

Arguments

  • ms (Number) A number between 10 and 10000.

Returns

this

AggregationCursor.next()

Returns the next result. Throws a RangeError is there are no more results. Use while ( cursor.hasNext() ) { cursor.next() } or for result of cursor loops to iterate cursors.

Returns

Object

AggregationCursor.passthru()

Opens a cursor (without fetching any results) which can be returned from a route script and streamed directly through the api. When returned, the script is detached and the cursor remains open until it's exhausted, incurring no further script ops or serialization costs. This is ideal for returning query results that do not require any post-query in-script processing.

- Without passthru: return org.objects.c_example.aggregate().toList() (script->api->script->api->response)
- With passthru: return org.objects.c_example.aggregate().limit(10).passthru() (script->api->response)

Returns

Object

AggregationCursor.pathPrefix(path = null)

Sets the pipeline prefix for retrieving a nested List property. All cursor options are passed through the path down to the list (including grant and skipAcl). Compatible with next(), toArray(), and with passthru() (to retrieve a streamable cursor). For example, org.objects.c_grandparent.aggregate().pathPrefix( '5a2c44bc8664e438e45387d5.c_parents.5a2c44f88664e438e45387d6.c_children' ).match( {c_prop: value} ) passes the match() option down through 2 list properties to the c_parents.c_children.

Arguments

  • path (String) Path to a list property.

Returns

Object

AggregationCursor.project(object)

Adds a $project stage to the aggregation.

Arguments