Products Customers Pricing Docs Help Blog
REST API Guide
Browse All Platforms More Platforms

Getting Started

The REST API lets you interact with Parse from anything that can send an HTTP request. There are many things you can do with the REST API. For example:

Want to contribute to this doc? Edit this section.
Was this section helpful? NO YES Thanks for your feedback, we’re always working to make our docs better.

Quick Reference

All API access is over HTTPS, and accessed via the https://api.parse.com domain. The relative path prefix /1/ indicates that we are currently using version 1 of the API.

Objects

URL HTTP Verb Functionality
/1/classes/<className> POST Creating Objects
/1/classes/<className>/<objectId> GET Retrieving Objects
/1/classes/<className>/<objectId> PUT Updating Objects
/1/classes/<className> GET Queries
/1/classes/<className>/<objectId> DELETE Deleting Objects

Users

URL HTTP Verb Functionality
/1/users POST Signing Up
Linking Users
/1/login GET Logging In
/1/logout POST Logging Out
/1/users/<objectId> GET Retrieving Users
/1/users/me GET Validating Session Tokens
Retrieving Current User
/1/users/<objectId> PUT Updating Users
Linking Users
Verifying Emails
/1/users GET Querying Users
/1/users/<objectId> DELETE Deleting Users
/1/requestPasswordReset POST Requesting A Password Reset

Sessions

URL HTTP Verb Functionality
/1/sessions POST Creating Restricted Sessions
/1/sessions/<objectId> GET Retrieving Sessions
/1/sessions/me GET Retrieving Current Session
/1/sessions/<objectId> PUT Updating Sessions
/1/users GET Querying Sessions
/1/sessions/<objectId> DELETE Deleting Sessions
/1/sessions/me PUT Pairing with Installation

Roles

URL HTTP Verb Functionality
/1/roles POST Creating Roles
/1/roles/<objectId> GET Retrieving Roles
/1/roles/<objectId> PUT Updating Roles
/1/roles/<objectId> DELETE Deleting Roles

Files

URL HTTP Verb Functionality
/1/files/<fileName> POST Uploading Files

Analytics

URL HTTP Verb Functionality
/1/events/AppOpened POST Analytics
/1/events/<eventName> POST Custom Analytics

Push Notifications

URL HTTP Verb Functionality
/1/push POST Push Notifications

Installations

URL HTTP Verb Functionality
/1/installations POST Uploading Installation Data
/1/installations/<objectId> GET Retrieving Installations
/1/installations/<objectId> PUT Updating Installations
/1/installations GET Querying Installations
/1/installations/<objectId> DELETE Deleting Installations

Cloud Functions

URL HTTP Verb Functionality
/1/functions/<name> POST Calling Cloud Functions
/1/jobs/<name> POST Triggering Background Jobs

Request Format

For POST and PUT requests, the request body must be JSON, with the Content-Type header set to application/json.

Authentication is done via HTTP headers. The X-Parse-Application-Id header identifies which application you are accessing, and the X-Parse-REST-API-Key header authenticates the endpoint.

In the examples that follow, the keys for your app are included in the command. You can use the drop-down to construct example code for other apps.

You may also authenticate your REST API requests using basic HTTP authentication. For example, to retrieve an object you could set the URL using your Parse credentials in the following format:

https://myAppID:javascript-key=myJavaScriptKey@api.parse.com/1/classes/GameScore/Ed1nuqPvcm

For Javascript usage, the Parse Cloud supports cross-origin resource sharing, so that you can use these headers in conjunction with XMLHttpRequest.

Response Format

The response format for all requests is a JSON object.

Whether a request succeeded is indicated by the HTTP status code. A 2xx status code indicates success, whereas a 4xx status code indicates failure. When a request fails, the response body is still JSON, but always contains the fields code and error which you can inspect to use for debugging. For example, trying to save an object with invalid keys will return the message:

{
  "code": 105,
  "error": "invalid field name: bl!ng"
}

Calling from Client Apps

You should not use the REST API Key in client apps (i.e. code you distribute to your customers). If the Parse SDK is available for your client platform, we recommend using our SDK instead of the REST API. If you must call the REST API directly from the client, you should use the corresponding client-side Parse key for that plaform (e.g. JavaScript Key, Client Key for iOS/Android, or Windows Key). If there is no Parse SDK for your client platform, please use your app's Client Key to call the REST API. Requests made with the Client Key, JavaScript Key, or Windows Key are restricted by client-side app settings that you configure in your Parse.com app dashboard. These settings make your app more secure. For example, turning off the "Client Push Enabled" setting will prevent push notifications from being sent from any device using the Client Key, JavaScript Key, or Windows Key (recommended for all production apps). Therefore, you should not distribute any app code with the REST API key embedded in it.

Want to contribute to this doc? Edit this section.
Was this section helpful? NO YES Thanks for your feedback, we’re always working to make our docs better.

Objects

Object Format

Storing data through the Parse REST API is built around a JSON encoding of the object's data. This data is schemaless, which means that you don't need to specify ahead of time what keys exist on each object. You simply set whatever key-value pairs you want, and the backend will store it.

For example, let's say you're tracking high scores for a game. A single object could contain:

{
  "score": 1337,
  "playerName": "Sean Plott",
  "cheatMode": false
}

Keys must be alphanumeric strings. Values can be anything that can be JSON-encoded.

Each object has a class name that you can use to distinguish different sorts of data. For example, we could call the high score object a GameScore. We recommend that you NameYourClassesLikeThis and nameYourKeysLikeThis, just to keep your code looking pretty.

When you retrieve objects from Parse, some fields are automatically added: createdAt, updatedAt, and objectId. These field names are reserved, so you cannot set them yourself. The object above could look like this when retrieved:

{
  "score": 1337,
  "playerName": "Sean Plott",
  "cheatMode": false,
  "createdAt": "2011-08-20T02:06:57.931Z",
  "updatedAt": "2011-08-20T02:06:57.931Z",
  "objectId": "Ed1nuqPvcm"
}

createdAt and updatedAt are UTC timestamps stored in ISO 8601 format with millisecond precision: YYYY-MM-DDTHH:MM:SS.MMMZ. objectId is a string unique to this class that identifies this object.

In the REST API, the class-level operations operate on a resource based on just the class name. For example, if the class name is GameScore, the class URL is:

https://api.parse.com/1/classes/GameScore

Users have a special class-level url:

https://api.parse.com/1/users

The operations specific to a single object are available a nested URL. For example, operations specific to the GameScore above with objectId equal to Ed1nuqPvcm would use the object URL:

https://api.parse.com/1/classes/GameScore/Ed1nuqPvcm

Creating Objects

To create a new object on Parse, send a POST request to the class URL containing the contents of the object. For example, to create the object described above:

  curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"score":1337,"playerName":"Sean Plott","cheatMode":false}' \
  https://api.parse.com/1/classes/GameScore
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/classes/GameScore', json.dumps({
       "score": 1337,
       "playerName": "Sean Plott",
       "cheatMode": False
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print results

When the creation is successful, the HTTP response is a 201 Created and the Location header contains the object URL for the new object:

Status: 201 Created
Location: https://api.parse.com/1/classes/GameScore/Ed1nuqPvcm

The response body is a JSON object containing the objectId and the createdAt timestamp of the newly-created object:

{
  "createdAt": "2011-08-20T02:06:57.931Z",
  "objectId": "Ed1nuqPvcm"
}

Retrieving Objects

Once you've created an object, you can retrieve its contents by sending a GET request to the object URL returned in the location header. For example, to retrieve the object we created above:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  https://api.parse.com/1/classes/GameScore/Ed1nuqPvcm
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('GET', '/1/classes/GameScore/Ed1nuqPvcm', '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

The response body is a JSON object containing all the user-provided fields, plus the createdAt, updatedAt, and objectId fields:

{
  "score": 1337,
  "playerName": "Sean Plott",
  "cheatMode": false,
  "skills": [
    "pwnage",
    "flying"
  ],
  "createdAt": "2011-08-20T02:06:57.931Z",
  "updatedAt": "2011-08-20T02:06:57.931Z",
  "objectId": "Ed1nuqPvcm"
}

When retrieving objects that have pointers to children, you can fetch child objects by using the include option. For instance, to fetch the object pointed to by the "game" key:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'include=game' \
  https://api.parse.com/1/classes/GameScore/Ed1nuqPvcm
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"include":"game"})
connection.connect()
connection.request('GET', '/1/classes/GameScore/Ed1nuqPvcm?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

Updating Objects

To change the data on an object that already exists, send a PUT request to the object URL. Any keys you don't specify will remain unchanged, so you can update just a subset of the object's data. For example, if we wanted to change the score field of our object:

curl -X PUT \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"score":73453}' \
  https://api.parse.com/1/classes/GameScore/Ed1nuqPvcm
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('PUT', '/1/classes/GameScore/Ed1nuqPvcm', json.dumps({
       "score": 73453
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

The response body is a JSON object containing just an updatedAt field with the timestamp of the update.

{
  "updatedAt": "2011-08-21T18:02:52.248Z"
}

Counters

To help with storing counter-type data, Parse provides the ability to atomically increment (or decrement) any number field. So, we can increment the score field like so:

curl -X PUT \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"score":{"__op":"Increment","amount":1}}' \
  https://api.parse.com/1/classes/GameScore/Ed1nuqPvcm
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('PUT', '/1/classes/GameScore/Ed1nuqPvcm', json.dumps({
       "score": {
         "__op": "Increment",
         "amount": 1
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

To decrement the counter, use the Increment operator with a negative number:

curl -X PUT \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"score":{"__op":"Increment","amount":-1}}' \
  https://api.parse.com/1/classes/GameScore/Ed1nuqPvcm
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('PUT', '/1/classes/GameScore/Ed1nuqPvcm', json.dumps({
       "score": {
         "__op": "Increment",
         "amount": -1
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

Arrays

To help with storing array data, there are three operations that can be used to atomically change an array field:

Each method takes an array of objects to add or remove in the "objects" key. For example, we can add items to the set-like "skills" field like so:

curl -X PUT \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"skills":{"__op":"AddUnique","objects":["flying","kungfu"]}}' \
  https://api.parse.com/1/classes/GameScore/Ed1nuqPvcm
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('PUT', '/1/classes/GameScore/Ed1nuqPvcm', json.dumps({
       "skills": {
         "__op": "AddUnique",
         "objects": [
           "flying",
           "kungfu"
         ]
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

Relations

In order to update Relation types, Parse provides special operators to atomically add and remove objects to a relation. So, we can add an object to a relation like so:

curl -X PUT \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"opponents":{"__op":"AddRelation","objects":[{"__type":"Pointer","className":"Player","objectId":"Vx4nudeWn"}]}}' \
  https://api.parse.com/1/classes/GameScore/Ed1nuqPvcm
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('PUT', '/1/classes/GameScore/Ed1nuqPvcm', json.dumps({
       "opponents": {
         "__op": "AddRelation",
         "objects": [
           {
             "__type": "Pointer",
             "className": "Player",
             "objectId": "Vx4nudeWn"
           }
         ]
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

To remove an object from a relation, you can do:

curl -X PUT \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"opponents":{"__op":"RemoveRelation","objects":[{"__type":"Pointer","className":"Player","objectId":"Vx4nudeWn"}]}}' \
  https://api.parse.com/1/classes/GameScore/Ed1nuqPvcm
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('PUT', '/1/classes/GameScore/Ed1nuqPvcm', json.dumps({
       "opponents": {
         "__op": "RemoveRelation",
         "objects": [
           {
             "__type": "Pointer",
             "className": "Player",
             "objectId": "Vx4nudeWn"
           }
         ]
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

Deleting Objects

To delete an object from the Parse Cloud, send a DELETE request to its object URL. For example:

curl -X DELETE \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  https://api.parse.com/1/classes/GameScore/Ed1nuqPvcm
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('DELETE', '/1/classes/GameScore/Ed1nuqPvcm', '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

You can delete a single field from an object by using the Delete operation:

curl -X PUT \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"opponents":{"__op":"Delete"}}' \
  https://api.parse.com/1/classes/GameScore/Ed1nuqPvcm
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('PUT', '/1/classes/GameScore/Ed1nuqPvcm', json.dumps({
       "opponents": {
         "__op": "Delete"
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

Batch Operations

To reduce the amount of time spent on network round trips, you can create, update, or delete up to 50 objects in one call, using the batch endpoint.

Each command in a batch has method, path, and body parameters that specify the HTTP command that would normally be used for that command. The commands are run in the order they are given. For example, to create a couple of GameScore objects:

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "requests": [
          {
            "method": "POST",
            "path": "/1/classes/GameScore",
            "body": {
              "score": 1337,
              "playerName": "Sean Plott"
            }
          },
          {
            "method": "POST",
            "path": "/1/classes/GameScore",
            "body": {
              "score": 1338,
              "playerName": "ZeroCool"
            }
          }
        ]
      }' \
  https://api.parse.com/1/batch
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/batch', json.dumps({
       "requests": [
         {
           "method": "POST",
           "path": "/1/classes/GameScore",
           "body": {
             "score": 1337,
             "playerName": "Sean Plott"
           }
         },
         {
           "method": "POST",
           "path": "/1/classes/GameScore",
           "body": {
             "score": 1338,
             "playerName": "ZeroCool"
           }
         }
       ]
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

The response from batch will be a list with the same number of elements as the input list. Each item in the list with be a dictionary with either the success or error field set. The value of success will be the normal response to the equivalent REST command:

{
  "success": {
    "createdAt": "2012-06-15T16:59:11.276Z",
    "objectId": "YAfSAWwXbL"
  }
}

The value of error will be an object with a numeric code and error string:

{
  "error": {
    "code": 101,
    "error": "object not found for delete"
  }
}

Other commands that work in a batch are update and delete.

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "requests": [
          {
            "method": "PUT",
            "path": "/1/classes/GameScore/Ed1nuqPvcm",
            "body": {
              "score": 999999
            }
          },
          {
            "method": "DELETE",
            "path": "/1/classes/GameScore/Cpl9lrueY5"
          }
        ]
      }' \
  https://api.parse.com/1/batch
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/batch', json.dumps({
       "requests": [
         {
           "method": "PUT",
           "path": "/1/classes/GameScore/Ed1nuqPvcm",
           "body": {
             "score": 999999
           }
         },
         {
           "method": "DELETE",
           "path": "/1/classes/GameScore/Cpl9lrueY5"
         }
       ]
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

Note that N requests sent in a batch will still count toward your request limit as N requests.

Data Types

So far we have only used values that can be encoded with standard JSON. The Parse mobile client libraries also support dates, binary data, and relational data. In the REST API, these values are encoded as JSON hashes with the __type field set to indicate their type, so you can read or write these fields if you use the correct encoding.

The Date type contains a field iso which contains a UTC timestamp stored in ISO 8601 format with millisecond precision: YYYY-MM-DDTHH:MM:SS.MMMZ.

{
  "__type": "Date",
  "iso": "2011-08-21T18:02:52.249Z"
}

Dates are useful in combination with the built-in createdAt and updatedAt fields. For example, to retrieve objects created since a particular time, just encode a Date in a comparison query:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'where={"createdAt":{"$gte":{"__type":"Date","iso":"2011-08-21T18:02:52.249Z"}}}' \
  https://api.parse.com/1/classes/GameScore
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"where":json.dumps({
       "createdAt": {
         "$gte": {
           "__type": "Date",
           "iso": "2011-08-21T18:02:52.249Z"
         }
       }
     })})
connection.connect()
connection.request('GET', '/1/classes/GameScore?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

The Bytes type contains a field base64 which contains a base64 encoding of binary data. The specific base64 encoding is the one used by MIME, and does not contain whitespace.

{
  "__type": "Bytes",
  "base64": "VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw=="
}

The Pointer type is used when mobile code sets a ParseObject or ParseObject as the value of another object. It contains the className and objectId of the referred-to value.

{
  "__type": "Pointer",
  "className": "GameScore",
  "objectId": "Ed1nuqPvc"
}

Pointers to user objects have a className of _User. Prefixing with an underscore is forbidden for developer-defined classes and signifies the class is a special built-in.

The Relation type is used for many-to-many relations when the mobile uses PFRelation or ParseRelation as a value. It has a className that is the class name of the target objects.

{
  "__type": "Relation",
  "className": "GameScore"
}

When querying, Relation objects behave like arrays of Pointers. Any operation that is valid for arrays of pointers (other than include) works for Relation objects.

When more data types are added, they will also be represented as hashes with a __type field set, so you may not use this field yourself on JSON objects.

Want to contribute to this doc? Edit this section.
Was this section helpful? NO YES Thanks for your feedback, we’re always working to make our docs better.

Queries

Basic Queries

You can retrieve multiple objects at once by sending a GET request to the class URL. Without any URL parameters, this simply lists objects in the class:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  https://api.parse.com/1/classes/GameScore
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('GET', '/1/classes/GameScore', '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

The return value is a JSON object that contains a results field with a JSON array that lists the objects.

{
  "results": [
    {
      "playerName": "Jang Min Chul",
      "updatedAt": "2011-08-19T02:24:17.787Z",
      "cheatMode": false,
      "createdAt": "2011-08-19T02:24:17.787Z",
      "objectId": "A22v5zRAgd",
      "score": 80075
    },
    {
      "playerName": "Sean Plott",
      "updatedAt": "2011-08-21T18:02:52.248Z",
      "cheatMode": false,
      "createdAt": "2011-08-20T02:06:57.931Z",
      "objectId": "Ed1nuqPvcm",
      "score": 73453
    }
  ]
}

Query Constraints

There are several ways to put constraints on the objects found, using the where URL parameter. The value of the where parameter should be encoded JSON. Thus, if you look at the actual URL requested, it would be JSON-encoded, then URL-encoded. The simplest use of the where parameter is constraining the value for keys. For example, if we wanted to retrieve Sean Plott's scores that were not in cheat mode, we could do:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'where={"playerName":"Sean Plott","cheatMode":false}' \
  https://api.parse.com/1/classes/GameScore
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"where":json.dumps({
       "playerName": "Sean Plott",
       "cheatMode": False
     })})
connection.connect()
connection.request('GET', '/1/classes/GameScore?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

The values of the where parameter also support comparisons besides exact matching. Instead of an exact value, provide a hash with keys corresponding to the comparisons to do. The where parameter supports these options:

Key Operation
$lt Less Than
$lte Less Than Or Equal To
$gt Greater Than
$gte Greater Than Or Equal To
$ne Not Equal To
$in Contained In
$nin Not Contained in
$exists A value is set for the key
$select This matches a value for a key in the result of a different query
$dontSelect Requires that a key's value not match a value for a key in the result of a different query
$all Contains all of the given values

For example, to retrieve scores between 1000 and 3000, including the endpoints, we could issue:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'where={"score":{"$gte":1000,"$lte":3000}}' \
  https://api.parse.com/1/classes/GameScore
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"where":json.dumps({
       "score": {
         "$gte": 1000,
         "$lte": 3000
       }
     })})
connection.connect()
connection.request('GET', '/1/classes/GameScore?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

To retrieve scores equal to an odd number below 10, we could issue:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'where={"score":{"$in":[1,3,5,7,9]}}' \
  https://api.parse.com/1/classes/GameScore

To retrieve scores not by a given list of players we could issue:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'where={"playerName":{"$nin":["Jonathan Walsh","Dario Wunsch","Shawn Simon"]}}' \
  https://api.parse.com/1/classes/GameScore
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"where":json.dumps({
       "score": {
         "$in": [
           1,
           3,
           5,
           7,
           9
         ]
       }
     })})
connection.connect()
connection.request('GET', '/1/classes/GameScore?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

To retrieve documents with the score set, we could issue:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'where={"score":{"$exists":true}}' \
  https://api.parse.com/1/classes/GameScore
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"where":json.dumps({
       "playerName": {
         "$nin": [
           "Jonathan Walsh",
           "Dario Wunsch",
           "Shawn Simon"
         ]
       }
     })})
connection.connect()
connection.request('GET', '/1/classes/GameScore?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

To retrieve documents without the score set, we could issue:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'where={"score":{"$exists":false}}' \
  https://api.parse.com/1/classes/GameScore
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"where":json.dumps({
       "score": {
         "$exists": False
       }
     })})
connection.connect()
connection.request('GET', '/1/classes/GameScore?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

If you have a class containing sports teams and you store a user's hometown in the user class, you can issue one query to find the list of users whose hometown teams have winning records. The query would look like:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'where={"hometown":{"$select":{"query":{"className":"Team","where":{"winPct":{"$gt":0.5}}},"key":"city"}}}' \
  https://api.parse.com/1/classes/_User
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"where":json.dumps({
       "hometown": {
         "$select": {
           "query": {
             "className": "Team",
             "where": {
               "winPct": {
                 "$gt": 0.5
               }
             }
           },
           "key": "city"
         }
       }
     })})
connection.connect()
connection.request('GET', '/1/classes/_User?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

You can use the order parameter to specify a field to sort by. Prefixing with a negative sign reverses the order. Thus, to retrieve scores in ascending order:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'order=score' \
  https://api.parse.com/1/classes/GameScore
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"order":"score"})
connection.connect()
connection.request('GET', '/1/classes/GameScore?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

And to retrieve scores in descending order:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'order=-score' \
  https://api.parse.com/1/classes/GameScore
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"order":"-score"})
connection.connect()
connection.request('GET', '/1/classes/GameScore?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

You can sort by multiple fields by passing order a comma-separated list. To retrieve documents that are ordered by scores in ascending order and the names in descending order:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'order=score,-name' \
  https://api.parse.com/1/classes/GameScore
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"order":"score,-name"})
connection.connect()
connection.request('GET', '/1/classes/GameScore?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

You can use the limit and skip parameters for pagination. limit defaults to 100, but anything from 1 to 1000 is a valid limit. Thus, to retrieve 200 objects after skipping the first 400:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'limit=200' \
  --data-urlencode 'skip=400' \
  https://api.parse.com/1/classes/GameScore
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"limit":200,"skip":400})
connection.connect()
connection.request('GET', '/1/classes/GameScore?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

You can restrict the fields returned by passing keys a comma-separated list. To retrieve documents that contain only the score and playerName fields (and also special built-in fields such as objectId, createdAt, and updatedAt):

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'keys=score,playerName' \
  https://api.parse.com/1/classes/GameScore
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"keys":"score,playerName"})
connection.connect()
connection.request('GET', '/1/classes/GameScore?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

All of these parameters can be used in combination with each other.

Queries on Array Values

For keys with an array type, you can find objects where the key's array value contains 2 by:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'where={"arrayKey":2}' \
  https://api.parse.com/1/classes/RandomObject
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"where":json.dumps({
       "arrayKey": 2
     })})
connection.connect()
connection.request('GET', '/1/classes/RandomObject?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

You can also use the $all operator to find objects with an array field which contains each of the values 2, 3, and 4 by:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'where={"arrayKey":{"$all":[2,3,4]}}' \
  https://api.parse.com/1/classes/RandomObject
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"where":json.dumps({
       "arrayKey": {
         "$all": [
           2,
           3,
           4
         ]
       }
     })})
connection.connect()
connection.request('GET', '/1/classes/RandomObject?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

Relational Queries

There are several ways to issue queries for relational data. If you want to retrieve objects where a field matches a particular object, you can use a where clause with a Pointer encoded with __type just like you would use other data types. For example, if each Comment has a Post object in its post field, you can fetch comments for a particular Post:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'where={"post":{"__type":"Pointer","className":"Post","objectId":"8TOXdXf3tz"}}' \
  https://api.parse.com/1/classes/Comment
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"where":json.dumps({
       "post": {
         "__type": "Pointer",
         "className": "Post",
         "objectId": "8TOXdXf3tz"
       }
     })})
connection.connect()
connection.request('GET', '/1/classes/Comment?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

If you want to retrieve objects where a field contains an object that matches another query, you can use the $inQuery operator. Note that the default limit of 100 and maximum limit of 1000 apply to the inner query as well, so with large data sets you may need to construct queries carefully to get the desired behavior. For example, imagine you have Post class and a Comment class, where each Comment has a pointer to its parent Post. You can find comments on posts with images by doing:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'where={"post":{"$inQuery":{"where":{"image":{"$exists":true}},"className":"Post"}}}' \
  https://api.parse.com/1/classes/Comment
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"where":json.dumps({
       "post": {
         "$inQuery": {
           "where": {
             "image": {
               "$exists": True
             }
           },
           "className": "Post"
         }
       }
     })})
connection.connect()
connection.request('GET', '/1/classes/Comment?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

If you want to retrieve objects where a field contains an object that does not match another query, you can use the $notInQuery operator. Imagine you have Post class and a Comment class, where each Comment has a pointer to its parent Post. You can find comments on posts without images by doing:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'where={"post":{"$notInQuery":{"where":{"image":{"$exists":true}},"className":"Post"}}}' \
  https://api.parse.com/1/classes/Comment
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"where":json.dumps({
       "post": {
         "$notInQuery": {
           "where": {
             "image": {
               "$exists": True
             }
           },
           "className": "Post"
         }
       }
     })})
connection.connect()
connection.request('GET', '/1/classes/Comment?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

If you want to retrieve objects that are members of Relation field of a parent object, you can use the $relatedTo operator. Imagine you have a Post class and User class, where each Post can be liked by many users. If the Users that liked a Post were stored in a Relation on the post under the key "likes", you can find the users that liked a particular post by:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'where={"$relatedTo":{"object":{"__type":"Pointer","className":"Post","objectId":"8TOXdXf3tz"},"key":"likes"}}' \
  https://api.parse.com/1/users
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"where":json.dumps({
       "$relatedTo": {
         "object": {
           "__type": "Pointer",
           "className": "Post",
           "objectId": "8TOXdXf3tz"
         },
         "key": "likes"
       }
     })})
connection.connect()
connection.request('GET', '/1/users?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

In some situations, you want to return multiple types of related objects in one query. You can do this by passing the field to include in the include parameter. For example, let's say you are retrieving the last ten comments, and you want to retrieve their related posts at the same time:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'order=-createdAt' \
  --data-urlencode 'limit=10' \
  --data-urlencode 'include=post' \
  https://api.parse.com/1/classes/Comment
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"order":"-createdAt","limit":10,"include":"post"})
connection.connect()
connection.request('GET', '/1/classes/Comment?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

Instead of being represented as a Pointer, the post field is now expanded into the whole object. __type is set to Object and className is provided as well. For example, a Pointer to a Post could be represented as:

{
  "__type": "Pointer",
  "className": "Post",
  "objectId": "8TOXdXf3tz"
}

When the query is issued with an include parameter for the key holding this pointer, the pointer will be expanded to:

{
  "__type": "Object",
  "className": "Post",
  "objectId": "8TOXdXf3tz",
  "createdAt": "2011-12-06T20:59:34.428Z",
  "updatedAt": "2011-12-06T20:59:34.428Z",
  "otherFields": "willAlsoBeIncluded"
}

You can also do multi level includes using dot notation. If you wanted to include the post for a comment and the post's author as well you can do:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'order=-createdAt' \
  --data-urlencode 'limit=10' \
  --data-urlencode 'include=post.author' \
  https://api.parse.com/1/classes/Comment
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"order":"-createdAt","limit":10,"include":"post.author"})
connection.connect()
connection.request('GET', '/1/classes/Comment?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

You can issue a query with multiple fields included by passing a comma-separated list of keys as the include parameter.

Counting Objects

Caveat: Count queries are rate limited to a maximum of 160 requests per minute. They can also return inaccurate results for classes with more than 1,000 objects. Thus, it is preferable to architect your application to avoid this sort of count operation (by using counters, for example.)

If you are limiting your query, or if there are a very large number of results, and you want to know how many total results there are without returning them all, you can use the count parameter. For example, if you only care about the number of games played by a particular player:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'where={"playerName":"Jonathan Walsh"}' \
  --data-urlencode 'count=1' \
  --data-urlencode 'limit=0' \
  https://api.parse.com/1/classes/GameScore
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"where":json.dumps({
       "playerName": "Jonathan Walsh"
     }),"count":1,"limit":0})
connection.connect()
connection.request('GET', '/1/classes/GameScore?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

Since this requests a count as well as limiting to zero results, there will be a count but no results in the response.

{
  "results": [],
  "count": 1337
}

With a nonzero limit, that request would return results as well as the count.

Compound Queries

If you want to find objects that match one of several queries, you can use $or operator, with a JSONArray as its value. For instance, if you want to find players with either have a lot of wins or a few wins, you can do:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'where={"$or":[{"wins":{"$gt":150}},{"wins":{"$lt":5}}]}' \
  https://api.parse.com/1/classes/Player
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"where":json.dumps({
       "$or": [
         {
           "wins": {
             "$gt": 150
           }
         },
         {
           "wins": {
             "$lt": 5
           }
         }
       ]
     })})
connection.connect()
connection.request('GET', '/1/classes/Player?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

Any other constraints on the query are also applied to the object returned, so you can add other constraints to queries with $or.

Note that we do not, however, support GeoPoint or non-filtering constraints (e.g. nearSphere, within, limit, skip, sort, include) in the subqueries of the compound query.

Want to contribute to this doc? Edit this section.
Was this section helpful? NO YES Thanks for your feedback, we’re always working to make our docs better.

Users

Many apps have a unified login that works across the mobile app and other systems. Accessing user accounts through the REST API lets you build this functionality on top of Parse.

In general, users have the same features as other objects, such as the flexible schema. The differences are that user objects must have a username and password, the password is automatically encrypted and stored securely, and Parse enforces the uniqueness of the username and email fields.

Signing Up

Signing up a new user differs from creating a generic object in that the username and password fields are required. The password field is handled differently than the others; it is encrypted with bcrypt when stored in the Parse Cloud and never returned to any client request.

You can ask Parse to verify user email addresses in your application settings page. With this setting enabled, all new user registrations with an email field will generate an email confirmation at that address. You can check whether the user has verified their email with the emailVerified field.

To sign up a new user, send a POST request to the users root. You may add any additional fields. For example, to create a user with a specific phone number:

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "X-Parse-Revocable-Session: 1" \
  -H "Content-Type: application/json" \
  -d '{"username":"cooldude6","password":"p_n7!-e8","phone":"415-392-0202"}' \
  https://api.parse.com/1/users
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/users', json.dumps({
       "username": "cooldude6",
       "password": "p_n7!-e8",
       "phone": "415-392-0202"
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "X-Parse-Revocable-Session": "1",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

The X-Parse-Revocable-Session header tells Parse to return a revocable session even if your app has "Require Revocable Sessions" turned off (at Parse.com app settings page). This is useful for transitioning from legacy session tokens to revocable sessions when your existing mobile app also accesses the same Parse data. If "Require Revocable Sessions" is turned on (default for new apps), the X-Parse-Revocable-Session header is unnecessary. When you ask for a revocable session during signup, the Parse Cloud will automatically create a ParseSession object. On this request, you can also tell Parse to automatically attach an installation to that session by specifying the optional X-Parse-Installation-Id header with the installationId of that installation.

When the creation is successful, the HTTP response is a 201 Created and the Location header contains the URL for the new user:

Status: 201 Created
Location: https://api.parse.com/1/users/g7y9tkhB7O

The response body is a JSON object containing the objectId, the createdAt timestamp of the newly-created object, and the sessionToken which can be used to authenticate subsequent requests as this user:

{
  "createdAt": "2011-11-07T20:58:34.448Z",
  "objectId": "g7y9tkhB7O",
  "sessionToken": "r:pnktnjyb996sj4p156gjtp4im"
}

Logging In

After you allow users to sign up, you need to let them log in to their account with a username and password in the future. To do this, send a GET request to the /1/login endpoint with username and password as URL-encoded parameters:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "X-Parse-Revocable-Session: 1" \
  -G \
  --data-urlencode 'username=cooldude6' \
  --data-urlencode 'password=p_n7!-e8' \
  https://api.parse.com/1/login
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"username":"cooldude6","password":"p_n7!-e8"})
connection.connect()
connection.request('GET', '/1/login?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "X-Parse-Revocable-Session": "1"
     })
result = json.loads(connection.getresponse().read())
print result

The X-Parse-Revocable-Session header tells Parse to return a revocable session even if your app has "Require Revocable Sessions" turned off (at Parse.com app settings page). This is useful for transitioning from legacy session tokens to revocable sessions when your existing mobile app also accesses the same Parse data. If "Require Revocable Sessions" is turned on (default for new apps), the X-Parse-Revocable-Session header is unnecessary. When you ask for a revocable session during login, the Parse Cloud will automatically create a ParseSession object. On this request, you can also tell Parse to automatically attach an installation to that session by specifying the optional X-Parse-Installation-Id header with the installationId of that installation.

The response body is a JSON object containing all the user-provided fields except password. It also contains the createdAt, updatedAt, objectId, and sessionToken fields:

{
  "username": "cooldude6",
  "phone": "415-392-0202",
  "createdAt": "2011-11-07T20:58:34.448Z",
  "updatedAt": "2011-11-07T20:58:34.448Z",
  "objectId": "g7y9tkhB7O",
  "sessionToken": "r:pnktnjyb996sj4p156gjtp4im"
}

Verifying Emails

Enabling email verification in an application's settings allows the application to reserve part of its experience for users with confirmed email addresses. Email verification adds the emailVerified field to the User object. When a User's email is set or modified, emailVerified is set to false. Parse then emails the user a link which will set emailVerified to true.

There are three emailVerified states to consider:

  1. true - the user confirmed his or her email address by clicking on the link Parse emailed them. Users can never have a true value when the user account is first created.
  2. false - at the time the User object was last refreshed, the user had not confirmed his or her email address. If emailVerified is false, consider refreshing the User object.
  3. missing - the User was created when email verification was off or the User does not have an email.

Requesting A Password Reset

You can initiate password resets for users who have emails associated with their account. To do this, send a POST request to /1/requestPasswordReset endpoint with email in the body of the request:

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"email":"coolguy@iloveapps.com"}' \
  https://api.parse.com/1/requestPasswordReset
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/requestPasswordReset', json.dumps({
       "email": "coolguy@iloveapps.com"
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

If successful, the response body is an empty JSON object.

Retrieving Users

You can also retrieve the contents of a user object by sending a GET request to the URL returned in the location header when it was created. For example, to retrieve the user created above:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  https://api.parse.com/1/users/g7y9tkhB7O
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('GET', '/1/users/g7y9tkhB7O', '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

The response body is a JSON object containing all the user-provided fields except password. It also contains the createdAt, updatedAt, and objectId fields:

{
  "username": "cooldude6",
  "phone": "415-392-0202",
  "createdAt": "2011-11-07T20:58:34.448Z",
  "updatedAt": "2011-11-07T20:58:34.448Z",
  "objectId": "g7y9tkhB7O"
}

Validating Session Tokens / Retrieving Current User

With a valid session token, you can send a GET request to the /1/users/me endpoint to retrieve the user associated with that session token:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "X-Parse-Session-Token: r:pnktnjyb996sj4p156gjtp4im" \
  https://api.parse.com/1/users/me
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('GET', '/1/users/me', '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "X-Parse-Session-Token": "r:pnktnjyb996sj4p156gjtp4im"
     })
result = json.loads(connection.getresponse().read())
print result

The response matches the JSON object above for retrieving users. If the session token is not valid, an error object is returned:

{
  "code": 209,
  "error": "invalid session token"
}

Updating Users

In normal usage, nobody except the user is allowed to modify their own data. To authenticate themselves, the user must add a X-Parse-Session-Token header to the request with the session token provided by the signup or login method.

To change the data on a user that already exists, send a PUT request to the user URL. Any keys you don't specify will remain unchanged, so you can update just a subset of the user's data. username and password may be changed, but the new username must not already be in use.

For example, if we wanted to change the phone number for cooldude6:

curl -X PUT \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "X-Parse-Session-Token: r:pnktnjyb996sj4p156gjtp4im" \
  -H "Content-Type: application/json" \
  -d '{"phone":"415-369-6201"}' \
  https://api.parse.com/1/users/g7y9tkhB7O
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('PUT', '/1/users/g7y9tkhB7O', json.dumps({
       "phone": "415-369-6201"
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "X-Parse-Session-Token": "r:pnktnjyb996sj4p156gjtp4im",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

The response body is a JSON object containing just an updatedAt field with the timestamp of the update.

{
  "updatedAt": "2011-11-07T21:25:10.623Z"
}

Querying

You can retrieve multiple users at once by sending a GET request to the root users URL. Without any URL parameters, this simply lists users:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  https://api.parse.com/1/users
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('GET', '/1/users', '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

The return value is a JSON object that contains a results field with a JSON array that lists the objects.

{
  "results": [
    {
      "username": "bigglesworth",
      "phone": "650-253-0000",
      "createdAt": "2011-11-07T20:58:06.445Z",
      "updatedAt": "2011-11-07T20:58:06.445Z",
      "objectId": "3KmCvT7Zsb"
    },
    {
      "username": "cooldude6",
      "phone": "415-369-6201",
      "createdAt": "2011-11-07T20:58:34.448Z",
      "updatedAt": "2011-11-07T21:25:10.623Z",
      "objectId": "g7y9tkhB7O"
    }
  ]
}

All of the options for queries that work for regular objects also work for user objects, so check the section on Querying Objects for more details.

Deleting Users

To delete a user from the Parse Cloud, send a DELETE request to its URL. You must provide the X-Parse-Session-Token header to authenticate. For example:

curl -X DELETE \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "X-Parse-Session-Token: r:pnktnjyb996sj4p156gjtp4im" \
  https://api.parse.com/1/users/g7y9tkhB7O
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('DELETE', '/1/users/g7y9tkhB7O', '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "X-Parse-Session-Token": "r:pnktnjyb996sj4p156gjtp4im"
     })
result = json.loads(connection.getresponse().read())
print result

Linking Users

Parse allows you to link your users with services like Twitter and Facebook, enabling your users to sign up or log into your application using their existing identities. This is accomplished through the sign-up and update REST endpoints by providing authentication data for the service you wish to link to a user in the authData field. Once your user is associated with a service, the authData for the service will be stored with the user and is retrievable by logging in.

authData is a JSON object with keys for each linked service containing the data below. In each case, you are responsible for completing the authentication flow (e.g. OAuth 1.0a) to obtain the information the the service requires for linking.

Facebook authData

{
  "facebook": {
    "id": "user's Facebook id number as a string",
    "access_token": "an authorized Facebook access token for the user",
    "expiration_date": "token expiration date of the format: yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
  }
}

Learn more about Facebook login.

Twitter authData

{
  "twitter": {
    "id": "user's Twitter id number as a string",
    "screen_name": "user's Twitter screen name",
    "consumer_key": "your application's consumer key",
    "consumer_secret": "your application's consumer secret",
    "auth_token": "an authorized Twitter token for the user with your application",
    "auth_token_secret": "the secret associated with the auth_token"
  }
}

Learn more about Twitter login.

Anonymous user authData

{
  "anonymous": {
    "id": "random UUID with lowercase hexadecimal digits"
  }
}

Signing Up and Logging In

Signing a user up with a linked service and logging them in with that service uses the same POST request, in which the authData for the user is specified. For example, to sign up or log in with a user's Twitter account:

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "X-Parse-Revocable-Session: 1" \
  -H "Content-Type: application/json" \
  -d '{
        "authData": {
          "twitter": {
            "id": "12345678",
            "screen_name": "ParseIt",
            "consumer_key": "SaMpLeId3X7eLjjLgWEw",
            "consumer_secret": "SaMpLew55QbMR0vTdtOACfPXa5UdO2THX1JrxZ9s3c",
            "auth_token": "12345678-SaMpLeTuo3m2avZxh5cjJmIrAfx4ZYyamdofM7IjU",
            "auth_token_secret": "SaMpLeEb13SpRzQ4DAIzutEkCE2LBIm2ZQDsP3WUU"
          }
        }
      }' \
  https://api.parse.com/1/users
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/users', json.dumps({
       "authData": {
         "twitter": {
           "id": "12345678",
           "screen_name": "ParseIt",
           "consumer_key": "SaMpLeId3X7eLjjLgWEw",
           "consumer_secret": "SaMpLew55QbMR0vTdtOACfPXa5UdO2THX1JrxZ9s3c",
           "auth_token": "12345678-SaMpLeTuo3m2avZxh5cjJmIrAfx4ZYyamdofM7IjU",
           "auth_token_secret": "SaMpLeEb13SpRzQ4DAIzutEkCE2LBIm2ZQDsP3WUU"
         }
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "X-Parse-Revocable-Session": "1",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

The X-Parse-Revocable-Session header tells Parse to return a revocable session even if your app has "Require Revocable Sessions" turned off (at Parse.com app settings page). This is useful for transitioning from legacy session tokens to revocable sessions when your existing mobile app also accesses the same Parse data. If "Require Revocable Sessions" is turned on (default for new apps), the X-Parse-Revocable-Session header is unnecessary. When you ask for a revocable session during login or signup, the Parse Cloud will automatically create a ParseSession object. On this request, you can also tell Parse to automatically attach an installation to that session by specifying the optional X-Parse-Installation-Id header with the installationId of that installation.

Parse then verifies that the provided authData is valid and checks to see if a user is already associated with this data. If so, it returns a status code of 200 OK and the details (including a sessionToken for the user):

Status: 200 OK
Location: https://api.parse.com/1/users/uMz0YZeAqc

With a response body like:

{
  "username": "Parse",
  "createdAt": "2012-02-28T23:49:36.353Z",
  "updatedAt": "2012-02-28T23:49:36.353Z",
  "objectId": "uMz0YZeAqc",
  "sessionToken": "r:samplei3l83eerhnln0ecxgy5",
  "authData": {
    "twitter": {
      "id": "12345678",
      "screen_name": "ParseIt",
      "consumer_key": "SaMpLeId3X7eLjjLgWEw",
      "consumer_secret": "SaMpLew55QbMR0vTdtOACfPXa5UdO2THX1JrxZ9s3c",
      "auth_token": "12345678-SaMpLeTuo3m2avZxh5cjJmIrAfx4ZYyamdofM7IjU",
      "auth_token_secret": "SaMpLeEb13SpRzQ4DAIzutEkCE2LBIm2ZQDsP3WUU"
    }
  }
}

If the user has never been linked with this account, you will instead receive a status code of 201 Created, indicating that a new user was created:

Status: 201 Created
Location: https://api.parse.com/1/users/uMz0YZeAqc

The body of the response will contain the objectId, createdAt, sessionToken, and an automatically-generated unique username. For example:

{
  "username": "iwz8sna7sug28v4eyu7t89fij",
  "createdAt": "2012-02-28T23:49:36.353Z",
  "objectId": "uMz0YZeAqc",
  "sessionToken": "r:samplei3l83eerhnln0ecxgy5"
}

Linking

Linking an existing user with a service like Facebook or Twitter uses a PUT request to associate authData with the user. For example, linking a user with a Facebook account would use a request like this:

curl -X PUT \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "X-Parse-Session-Token: r:samplei3l83eerhnln0ecxgy5" \
  -H "Content-Type: application/json" \
  -d '{
        "authData": {
          "facebook": {
            "id": "123456789",
            "access_token": "SaMpLeAAibS7Q55FSzcERWIEmzn6rosftAr7pmDME10008bWgyZAmv7mziwfacNOhWkgxDaBf8a2a2FCc9Hbk9wAsqLYZBLR995wxBvSGNoTrEaL",
            "expiration_date": "2012-02-28T23:49:36.353Z"
          }
        }
      }' \
  https://api.parse.com/1/users/uMz0YZeAqc
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('PUT', '/1/users/uMz0YZeAqc', json.dumps({
       "authData": {
         "facebook": {
           "id": "123456789",
           "access_token": "SaMpLeAAibS7Q55FSzcERWIEmzn6rosftAr7pmDME10008bWgyZAmv7mziwfacNOhWkgxDaBf8a2a2FCc9Hbk9wAsqLYZBLR995wxBvSGNoTrEaL",
           "expiration_date": "2012-02-28T23:49:36.353Z"
         }
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "X-Parse-Session-Token": "r:samplei3l83eerhnln0ecxgy5",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

After linking your user to a service, you can authenticate them using matching authData.

Unlinking

Unlinking an existing user with a service also uses a PUT request to clear authData from the user by setting the authData for the service to null. For example, unlinking a user with a Facebook account would use a request like this:

curl -X PUT \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "X-Parse-Session-Token: r:samplei3l83eerhnln0ecxgy5" \
  -H "Content-Type: application/json" \
  -d '{
        "authData": {
          "facebook": null
        }
      }' \
  https://api.parse.com/1/users/uMz0YZeAqc
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('PUT', '/1/users/uMz0YZeAqc', json.dumps({
       "authData": {
         "facebook": null
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "X-Parse-Session-Token": "r:samplei3l83eerhnln0ecxgy5",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

Security

When you access Parse via the REST API key, access can be restricted by ACL just like in the iOS and Android SDKs. You can still read and modify acls via the REST API, just be accessing the "ACL" key of an object.

The ACL is formatted as a JSON object where the keys are either object ids or the special key "*" to indicate public access permissions. The values of the ACL are "permission objects", JSON objects whose keys are the permission names and whose values are always true.

For example, if you want the user with id "3KmCvT7Zsb" to have read and write access to an object, plus the object should be publicly readable, that corresponds to an ACL of:

{
  "3KmCvT7Zsb": {
    "read": true,
    "write": true
  },
  "*": {
    "read": true
  }
}

If you want to access your data ignoring all ACLs, you can use the master key provided on the Dashboard. Instead of the X-Parse-REST-API-Key header, set the X-Parse-Master-Key header. For backward compatibility, you can also do master-level authentication using HTTP Basic Auth, passing the application id as the username and the master key as the password. For security, the master key should not be distributed to end users, but if you are running code in a trusted environment, feel free to use the master key for authentication.

Want to contribute to this doc? Edit this section.
Was this section helpful? NO YES Thanks for your feedback, we’re always working to make our docs better.

Sessions

Session APIs are only available in apps with revocable sessions enabled. Parse apps created after March 25, 2015 have this enabled by default ("Require Revocable Sessions" toggle in your Parse.com app settings page). If you have an existing app, you can upgrade to revocable sessions by following the Session Migration Tutorial.

Sessions represent an instance of a user logged into a device. Sessions are automatically created when users log in or sign up. They are automatically deleted when users log out. There is one distinct ParseSession object for each user-installation pair; if a user issues a login request from a device they're already logged into, that user's previous ParseSession object for that Installation is automatically deleted. ParseSession objects are stored on Parse in the Session class, and you can view them on the Parse.com Data Browser. We provide a set of APIs to manage ParseSession objects in your app.

ParseSession is a subclass of ParseObject, so you can query, update, and delete sessions in the same way that you manipulate normal objects on Parse. Because the Parse Cloud automatically creates sessions when you log in or sign up users, you should not manually create ParseSession objects unless you are building a "Parse for IoT" app (e.g. Arduino or Embedded C). Deleting a ParseSession will log the user out of the device that is currently using this session's token.

Unlike other Parse objects, the ParseSession class does not have Cloud Code triggers. So you cannot register a beforeSave or afterSave handler for the Session class.

Properties

The ParseSession object has these special fields:

Handling Invalid Session Token Error

Apps created before March 25, 2015 use legacy session tokens until you migrate them to use the new revocable sessions. On API requests with legacy tokens, if the token is invalid (e.g. User object was deleted), then the request is executed as a non-logged in user and no error was returned. On API requests with revocable session tokens, an invalid session token will always fail with the "invalid session token" error. This new behavior lets you know when you need to ask the user to log in again.

With revocable sessions, your current session token could become invalid if its corresponding ParseSession object is deleted from the Parse Cloud. This could happen if you implement a Session Manager UI that lets users log out of other devices, or if you manually delete the session via Cloud Code, REST API, or Data Browser. Sessions could also be deleted due to automatic expiration (if configured in app settings). When a device's session token no longer corresponds to a ParseSession object on the Parse Cloud, all API requests from that device will fail with “Error 209: invalid session token”.

Creating Sessions

For mobile apps and websites, you should not create ParseSession objects manually. Instead, you should call GET /1/login and POST /1/users (signup), which will automatically generate a ParseSession object in the Parse Cloud. The session token for this automatically-created session will be sent back on the login and signup response. Same for Facebook/Twitter login and signup requests.

In "Parse for IoT" apps (e.g. Arduino or Embedded C), you may want to programmatically create a restricted session that can be transferred to an IoT device. In order to do this, you must first log in normally to obtain an unrestricted session token. Then, you can create a restricted session by providing this unrestricted session token:

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "X-Parse-Session-Token: r:pnktnjyb996sj4p156gjtp4im" \
  -H "Content-Type: application/json" \
  -d '{"customField":"value"}' \
  https://api.parse.com/1/sessions
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/sessions', json.dumps({
       "customField": "value"
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "X-Parse-Session-Token": "r:pnktnjyb996sj4p156gjtp4im",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

In the above code, r:pnktnjyb996sj4p156gjtp4im is the unrestricted session token from the original user login.

The response looks like:

{
  "createdAt": "2015-03-25T18:21:52.883Z",
  "createdWith": {
    "action": "create"
  },
  "objectId": "pla1TY9co3",
  "restricted": true,
  "sessionToken": "r:aVrtljyb7E8xKo9256gfvp4n2"
}

At this point, you can pass the session token r:aVrtljyb7E8xKo9256gfvp4n2 to an IoT device so that it can access the current user's data.

Retrieving Sessions

If you have the session's objectId, you fetch the ParseSession object as long as it belongs to the same user as your current session:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "X-Parse-Session-Token: r:pnktnjyb996sj4p156gjtp4im" \
  https://api.parse.com/1/sessions/Axy98kq1B09
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('GET', '/1/sessions/Axy98kq1B09', '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "X-Parse-Session-Token": "r:pnktnjyb996sj4p156gjtp4im"
     })
result = json.loads(connection.getresponse().read())
print result

If you only have the session's token (from previous login or session create), you can validate and fetch the corresponding session by:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "X-Parse-Session-Token: r:pnktnjyb996sj4p156gjtp4im" \
  https://api.parse.com/1/sessions/me
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('GET', '/1/sessions/me', '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "X-Parse-Session-Token": "r:pnktnjyb996sj4p156gjtp4im"
     })
result = json.loads(connection.getresponse().read())
print result

Updating Sessions

Updating a session is analogous to updating a Parse object.

curl -X PUT \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "X-Parse-Session-Token: r:pnktnjyb996sj4p156gjtp4im" \
  -H "Content-Type: application/json" \
  -d '{"customField":"value"}' \
  https://api.parse.com/1/sessions/Axy98kq1B09
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/logout', '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "X-Parse-Session-Token": "r:pnktnjyb996sj4p156gjtp4im"
     })
result = json.loads(connection.getresponse().read())
print result

Querying Sessions

Querying for ParseSession objects will only return objects belonging to the same user as your current session (due to the Session ACL). You can also add a where clause to your query, just like normal Parse objects.

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "X-Parse-Session-Token: r:pnktnjyb996sj4p156gjtp4im" \
  https://api.parse.com/1/sessions
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('GET', '/1/sessions', '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "X-Parse-Session-Token": "r:pnktnjyb996sj4p156gjtp4im"
     })
result = json.loads(connection.getresponse().read())
print result

Deleting Sessions

Deleting the Session object will revoke its session token and cause the user to be logged out on the device that's currently using this session token. When you have the session token, then you can delete its ParseSession object by calling the logout endpoint:

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "X-Parse-Session-Token: r:pnktnjyb996sj4p156gjtp4im" \
  https://api.parse.com/1/logout
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/logout', '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "X-Parse-Session-Token": "r:pnktnjyb996sj4p156gjtp4im"
     })
result = json.loads(connection.getresponse().read())
print result

If you want to delete another ParseSession object for your user, and you have its objectId, you can delete it (but not log yourself out) by:

curl -X DELETE \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "X-Parse-Session-Token: r:pnktnjyb996sj4p156gjtp4im" \
  https://api.parse.com/1/sessions/Axy98kq1B09
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('DELETE', '/1/sessions/Axy98kq1B09', '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "X-Parse-Session-Token": "r:pnktnjyb996sj4p156gjtp4im"
     })
result = json.loads(connection.getresponse().read())
print result

X-Parse-Session-Token authenticates the request as the user that also owns session Axy98kq1B09, which may have a different session token. You can only delete other sessions that belong to the same user.

Pairing Session with Installation

For normal user login with the /1/login endpoint, the Parse Cloud will set the automatically-created ParseSession object's installationId to the X-Parse-Installation-Id header passed on the login or signup request. Therefore, for these scenarios, you don't need to manually associate the ParseSession object with an installation.

The following API is most useful for "Parse for IoT" apps (e.g. Arduino or Embedded C). During IoT device provisioning, the phone typically does not know the installationId of the IoT device. The provisioning process typically goes like this:

  1. Phone creates a restricted session (with blank installationId) for the device.
  2. IoT device acts as a Wi-Fi software access point. Phone passes this newly-created session's token, along with the Wi-Fi password, to the IoT device.
  3. IoT device connects to Internet via Wi-Fi, saves its ParseInstallation object.
  4. IoT device calls the following endpoint to associate the its installationId with its session. This endpoint only works with session tokens from restricted sessions. Please note that REST API calls from an IoT device should use the Client Key, not the REST API Key.
curl -X PUT \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-Client-Key: ${CLIENT_KEY}" \
  -H "X-Parse-Session-Token: r:aVrtljyb7E8xKo9256gfvp4n2" \
  -H "X-Parse-Installation-Id: 2d3777a5-f5fc-4caf-80be-73c766235afb" \
  -H "Content-Type: application/json" \
  -d '{}' \
  https://api.parse.com/1/sessions/me
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('PUT', '/1/sessions/me', json.dumps({
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "X-Parse-Session-Token": "r:aVrtljyb7E8xKo9256gfvp4n2",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

Security

ParseSession objects can only be accessed by the user specified in the user field. All ParseSession objects have an ACL that is read and write by that user only. You cannot change this ACL. This means querying for sessions will only return objects that match the current logged-in user.

When you log in a user via /1/login, Parse will automatically create a new unrestricted ParseSession object in the Parse Cloud. Same for signups and Facebook/Twitter logins.

Session objects manually created from POST /1/sessions are always restricted. You cannot manually create an unrestricted sessions using the object creation API.

Restricted sessions are prohibited from creating, modifying, or deleting any data in the ParseUser, ParseSession, and ParseRole classes. Restricted session also cannot read unrestricted sessions. Restricted Sessions are useful for "Parse for IoT" devices (e.g Arduino or Embedded C) that may run in a less-trusted physical environment than mobile apps. However, please keep in mind that restricted sessions can still read data on ParseUser, ParseSession, and ParseRole classes, and can read/write data in any other class just like a normal session. So it is still important for IoT devices to be in a safe physical environment and ideally use encrypted storage to store the session token.

If you want to prevent restricted Sessions from modifying classes other than ParseUser, ParseSession, or ParseRole, you can write a Cloud Code beforeSave handler for that class:

Parse.Cloud.beforeSave("MyClass", function(request, response) {
  Parse.Session.current().then(function(session) {
    if (session.get('restricted')) {
      response.error('write operation not allowed');
    }
    response.success();
  });
});

You can configure Class-Level Permissions (CLPs) for the Session class just like other classes on Parse. CLPs restrict reading/writing of sessions via the /1/sessions API, but do not restrict Parse Cloud's automatic session creation/deletion when users log in, sign up, and log out. We recommend that you disable all CLPs not needed by your app. Here are some common use cases for Session CLPs:

Want to contribute to this doc? Edit this section.
Was this section helpful? NO YES Thanks for your feedback, we’re always working to make our docs better.

Roles

As your app grows in scope and user-base, you may find yourself needing more coarse-grained control over access to pieces of your data than user-linked ACLs can provide. To address this requirement, Parse supports a form of Role-based Access Control. Roles provide a logical way of grouping users with common access privileges to your Parse data. Roles are named objects that contain users and other roles. Any permission granted to a role is implicitly granted to its users as well as to the users of any roles that it contains.

For example, in your application with curated content, you may have a number of users that are considered "Moderators" and can modify and delete content created by other users. You may also have a set of users that are "Administrators" and are allowed all of the same privileges as Moderators, but can also modify the global settings for the application. By adding users to these roles, you can ensure that new users can be made moderators or administrators, without having to manually grant permission to every resource for each user.

We provide a specialized role class to represent these groupings of users for the purposes of assigning permissions. Roles have a few special fields that set them apart from other objects.

Often, in order to keep these roles secure, your mobile apps won't be directly responsible for managing creation and membership of your roles. Instead, roles may be managed by a separate interface on the web or manually managed by an administrator. Our REST API allows you to manage your roles without requiring a mobile client.

Creating Roles

Creating a new role differs from creating a generic object in that the name field is required. Roles must also specify an ACL, which should be as restrictive as possible to avoid allowing the wrong users to modify a role.

To create a new role, send a POST request to the roles root:

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "name": "Moderators",
        "ACL": {
          "*": {
            "read": true
          }
        }
      }' \
  https://api.parse.com/1/roles
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/roles', json.dumps({
       "name": "Moderators",
       "ACL": {
         "*": {
           "read": True
         }
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

You can create a role with child roles or users by adding existing objects to the roles and users relations:

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "name": "Moderators",
        "ACL": {
          "*": {
            "read": true
          }
        },
        "roles": {
          "__op": "AddRelation",
          "objects": [
            {
              "__type": "Pointer",
              "className": "_Role",
              "objectId": "Ed1nuqPvc"
            }
          ]
        },
        "users": {
          "__op": "AddRelation",
          "objects": [
            {
              "__type": "Pointer",
              "className": "_User",
              "objectId": "8TOXdXf3tz"
            }
          ]
        }
      }' \
  https://api.parse.com/1/roles
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/roles', json.dumps({
       "name": "Moderators",
       "ACL": {
         "*": {
           "read": True
         }
       },
       "roles": {
         "__op": "AddRelation",
         "objects": [
           {
             "__type": "Pointer",
             "className": "_Role",
             "objectId": "Ed1nuqPvc"
           }
         ]
       },
       "users": {
         "__op": "AddRelation",
         "objects": [
           {
             "__type": "Pointer",
             "className": "_User",
             "objectId": "8TOXdXf3tz"
           }
         ]
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

When the creation is successful, the HTTP response is a 201 Created and the Location header contains the object URL for the new object:

Status: 201 Created
Location: https://api.parse.com/1/roles/mrmBZvsErB

The response body is a JSON object containing the objectId and createdAt timestamp of the newly-created object:

{
  "createdAt": "2012-04-28T17:41:09.106Z",
  "objectId": "mrmBZvsErB"
}

Retrieving Roles

You can also retrieve the contents of a role object by sending a GET request to the URL returned in the location header when it was created. For example, to retrieve the role created above:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  https://api.parse.com/1/roles/mrmBZvsErB
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('GET', '/1/roles/mrmBZvsErB', '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

The response body is a JSON object containing all of the fields on the role:

{
  "createdAt": "2012-04-28T17:41:09.106Z",
  "objectId": "mrmBZvsErB",
  "updatedAt": "2012-04-28T17:41:09.106Z",
  "ACL": {
    "*": {
      "read": true
    },
    "role:Administrators": {
      "write": true
    }
  },
  "name": "Moderators"
}

Note that the users and roles relations will not be visible in this JSON. Instead, you must query for the roles and users that belong to a given role using the $relatedTo operator.

Updating Roles

Updating a role generally works like updating any other object, but the name field on the role cannot be changed. Adding and removing users and roles to the users and roles relations can be accomplished by using the AddRelation and RemoveRelation operators.

For example, we can add two users to the "Moderators" role created above like so:

curl -X PUT \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-Master-Key: ${MASTER_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "users": {
          "__op": "AddRelation",
          "objects": [
            {
              "__type": "Pointer",
              "className": "_User",
              "objectId": "8TOXdXf3tz"
            },
            {
              "__type": "Pointer",
              "className": "_User",
              "objectId": "g7y9tkhB7O"
            }
          ]
        }
      }' \
  https://api.parse.com/1/roles/mrmBZvsErB
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('PUT', '/1/roles/mrmBZvsErB', json.dumps({
       "users": {
         "__op": "AddRelation",
         "objects": [
           {
             "__type": "Pointer",
             "className": "_User",
             "objectId": "8TOXdXf3tz"
           },
           {
             "__type": "Pointer",
             "className": "_User",
             "objectId": "g7y9tkhB7O"
           }
         ]
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-Master-Key": "${MASTER_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

Similarly, we can remove a child role from the "Moderators" role created above like so:

curl -X PUT \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-Master-Key: ${MASTER_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "roles": {
          "__op": "RemoveRelation",
          "objects": [
            {
              "__type": "Pointer",
              "className": "_Role",
              "objectId": "Ed1nuqPvc"
            }
          ]
        }
      }' \
  https://api.parse.com/1/roles/mrmBZvsErB
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('PUT', '/1/roles/mrmBZvsErB', json.dumps({
       "roles": {
         "__op": "RemoveRelation",
         "objects": [
           {
             "__type": "Pointer",
             "className": "_Role",
             "objectId": "Ed1nuqPvc"
           }
         ]
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-Master-Key": "${MASTER_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

Note that we've included the master key in the query above because the "Moderators" role has an ACL that restricts modification by the public.

Deleting Roles

To delete a role from the Parse Cloud, send a DELETE request to its URL. For example:

curl -X DELETE \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-Master-Key: ${MASTER_KEY}" \
  https://api.parse.com/1/roles/mrmBZvsErB
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('DELETE', '/1/roles/mrmBZvsErB', '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-Master-Key": "${MASTER_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

Again, we pass the master key in order to bypass the ACL on the role itself. Alternatively, we could pass an X-Parse-Session-Token for a user that has write access to the Role object (e.g. an Administrator). For example:

curl -X DELETE \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "X-Parse-Session-Token: pnktnjyb996sj4p156gjtp4im" \
  https://api.parse.com/1/roles/mrmBZvsErB
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('DELETE', '/1/roles/mrmBZvsErB', '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "X-Parse-Session-Token": "pnktnjyb996sj4p156gjtp4im"
     })
result = json.loads(connection.getresponse().read())
print result

Security

When you access Parse via the REST API key, access can be restricted by ACL just like in the iOS and Android SDKs. You can still read and modify ACLs via the REST API, just by accessing the "ACL" key of an object. In addition to per-user permissions as described above, you can also specify role-level permissions to your Parse objects. Instead of specifying an objectId as the key for a permission object as you do for users, you can instead specify a role's name with a "role:" prefix as the key for a permission object. You can use role-level permissions alongside user-level permissions to provide fine-grained control over user access.

For example, to restrict an object to be readable by anyone in the "Members" role and writable by its creator and anyone in the "Moderators" role, you would specify an ACL like this:

{
  "8TOXdXf3tz": {
    "write": true
  },
  "role:Members": {
    "read": true
  },
  "role:Moderators": {
    "write": true
  }
}

You are not required to specify read permissions for the user or the "Moderators" role if the user and role are already children of the "Members" role, since they will inherit read permissions granted to "Members".

Role Hierarchy

As described above, one role can contain another, establishing a parent-child relationship between the two roles. The consequence of this relationship is that any permission granted to the parent role is implicitly granted to all of its child roles.

These types of relationships are commonly found in applications with user-managed content, such as forums. Some small subset of users are "Administrators", with the highest level of access to tweaking the application's settings, creating new forums, setting global messages, and so on. Another set of users are "Moderators", who are responsible for ensuring that the content created by users remains appropriate. Any user with Administrator privileges should also be granted the permissions of any Moderator. To establish this relationship, you would make your "Administrators" role a child role of "Moderators" by adding the "Administrators" role to the roles relation on your "Moderators" object like this:

curl -X PUT \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-Master-Key: ${MASTER_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "roles": {
          "__op": "AddRelation",
          "objects": [
            {
              "__type": "Pointer",
              "className": "_Role",
              "objectId": "<AdministratorsRoleObjectId>"
            }
          ]
        }
      }' \
  https://api.parse.com/1/roles/<ModeratorsRoleObjectId>
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('PUT', '/1/roles/<ModeratorsRoleObjectId>', json.dumps({
       "roles": {
         "__op": "AddRelation",
         "objects": [
           {
             "__type": "Pointer",
             "className": "_Role",
             "objectId": "<AdministratorsRoleObjectId>"
           }
         ]
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-Master-Key": "${MASTER_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result
Want to contribute to this doc? Edit this section.
Was this section helpful? NO YES Thanks for your feedback, we’re always working to make our docs better.

Files

Uploading Files

To upload a file to Parse, send a POST request to the files URL, postfixed with the name of the file. The request must contain the Content-Type header associated with the file. Keep in mind that files are limited to 10 megabytes. Here's a simple example that'll create a file named hello.txt containing a string:

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: text/plain" \
  -d 'Hello, World!' \
  https://api.parse.com/1/files/hello.txt
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/files/hello.txt', 'Hello, World!', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "text/plain"
     })
result = json.loads(connection.getresponse().read())
print result

When the file upload is successful, the HTTP response is a 201 Created and the Location header which contains the URL for the file:

Status: 201 Created
Location: http://files.parsetfss.com/bc9f32df-2957-4bb1-93c9-ec47d9870a05/tfss-db295fb2-8a8b-49f3-aad3-dd911142f64f-hello.txt

The response body is a JSON object containing the name of the file, which is the original file name prefixed with a unique identifier in order to prevent name collisions. This means you can save files with the same name, and the files will not overwrite one another.

{
  "url": "http://files.parsetfss.com/bc9f32df-2957-4bb1-93c9-ec47d9870a05/tfss-db295fb2-8a8b-49f3-aad3-dd911142f64f-hello.txt",
  "name": "db295fb2-8a8b-49f3-aad3-dd911142f64f-hello.txt"
}

To upload an image, the syntax is a little bit different. Here's an example that will upload the image myPicture.jpg from the current directory.

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: image/jpeg" \
  --data-binary '@myPicture.jpg' \
  https://api.parse.com/1/files/pic.jpg
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/files/pic.jpg', open('myPicture.jpg', 'rb').read(), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "image/jpeg"
     })
result = json.loads(connection.getresponse().read())
print result

Associating with Objects

After files are uploaded, you can associate them with Parse objects:

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "name": "Andrew",
        "picture": {
          "name": "...profile.png",
          "__type": "File"
        }
      }' \
  https://api.parse.com/1/classes/PlayerProfile
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/classes/PlayerProfile', json.dumps({
       "name": "Andrew",
       "picture": {
         "name": "...profile.png",
         "__type": "File"
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

Note that the name of the file in the request is not the local file name, but the name in the response of the previous upload operation.

Deleting Files

Users holding the master key are allowed to delete files using the REST API. To delete a file, send a DELETE request to the files URL, postfixed with the name of the file. Note that the name of the file must be the name in the response of the upload operation, rather than the original filename. Note that the X-Parse-Master-Key must be provided in headers.

curl -X DELETE \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-Master-Key: ${MASTER_KEY}" \
  https://api.parse.com/1/files/...profile.png
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('DELETE', '/1/files/...profile.png', '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-Master-Key": "${MASTER_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

Note that deleting a PFObject with a file associated with it will not delete the file. All files stored on Parse should be deleted by using the above explained API.

Want to contribute to this doc? Edit this section.
Was this section helpful? NO YES Thanks for your feedback, we’re always working to make our docs better.

GeoPoints

Parse allows you to associate real-world latitude and longitude coordinates with an object. Adding a GeoPoint data type to a class allows queries to take into account the proximity of an object to a reference point. This allows you to easily do things like find out what user is closest to another user or which places are closest to a user.

GeoPoint

To associate a point with an object you will need to embed a GeoPoint data type into your object. This is done by using a JSON object with __type set to the string GeoPoint and numeric values being set for the latitude and longitude keys. For example, to create an object containing a point under the "location" key with a latitude of 40.0 degrees and -30.0 degrees longitude:

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "location": {
          "__type": "GeoPoint",
          "latitude": 40.0,
          "longitude": -30.0
        }
      }' \
  https://api.parse.com/1/classes/PlaceObject
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/classes/PlaceObject', json.dumps({
       "location": {
         "__type": "GeoPoint",
         "latitude": 40.0,
         "longitude": -30.0
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

Geo Queries

Now that you have a bunch of objects with spatial coordinates, it would be nice to find out which objects are closest to a point. This can be done by using a GeoPoint data type with query on the field using $nearSphere. Getting a list of ten places that are closest to a user may look something like:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'limit=10' \
  --data-urlencode 'where={
        "location": {
          "$nearSphere": {
            "__type": "GeoPoint",
            "latitude": 30.0,
            "longitude": -20.0
          }
        }
      }' \
  https://api.parse.com/1/classes/PlaceObject
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"limit":10,"where":json.dumps({
       "location": {
         "$nearSphere": {
           "__type": "GeoPoint",
           "latitude": 30.0,
           "longitude": -20.0
         }
       }
     })})
connection.connect()
connection.request('GET', '/1/classes/PlaceObject?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

This will return a list of results ordered by distance from 30.0 latitude and -20.0 longitude. The first result will be the nearest object. (Note that if an explicit order parameter is supplied, it will take precedence over the distance ordering.) For example, here are two results returned for the above query:

{
  "results": [
    {
      "location": {
        "latitude": 40.0,
        "__type": "GeoPoint",
        "longitude": -30.0
      },
      "updatedAt": "2011-12-06T22:36:04.983Z",
      "createdAt": "2011-12-06T22:36:04.983Z",
      "objectId": "iFEPN5Gwoz"
    },
    {
      "location": {
        "latitude": 60.0,
        "__type": "GeoPoint",
        "longitude": -20.0
      },
      "updatedAt": "2011-12-06T22:36:26.143Z",
      "createdAt": "2011-12-06T22:36:26.143Z",
      "objectId": "LAyNKSNTHT"
    }
  ]
}

To limit the search to a maximum distance add a $maxDistanceInMiles (for miles), $maxDistanceInKilometers (for kms), or $maxDistanceInRadians (for radian angle), term to the key constraint. For example, the following limits the radius to 10 miles:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'where={
        "location": {
          "$nearSphere": {
            "__type": "GeoPoint",
            "latitude": 30.0,
            "longitude": -20.0
          },
          "$maxDistanceInMiles": 10.0
        }
      }' \
  https://api.parse.com/1/classes/PlaceObject
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"where":json.dumps({
       "location": {
         "$nearSphere": {
           "__type": "GeoPoint",
           "latitude": 30.0,
           "longitude": -20.0
         },
         "$maxDistanceInMiles": 10.0
       }
     })})
connection.connect()
connection.request('GET', '/1/classes/PlaceObject?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

It's also possible to query for the set of objects that are contained within a particular area. To find the objects in a rectangular bounding box, add a clause to the key constraint with the format {"$within": {"$box": {[southwestGeoPoint, northeastGeoPoint]}}}.

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -G \
  --data-urlencode 'where={
        "location": {
          "$within": {
            "$box": [
              {
                "__type": "GeoPoint",
                "latitude": 37.71,
                "longitude": -122.53
              },
              {
                "__type": "GeoPoint",
                "latitude": 30.82,
                "longitude": -122.37
              }
            ]
          }
        }
      }' \
  https://api.parse.com/1/classes/PizzaPlaceObject
import json,httplib,urllib
connection = httplib.HTTPSConnection('api.parse.com', 443)
params = urllib.urlencode({"where":json.dumps({
       "location": {
         "$within": {
           "$box": [
             {
               "__type": "GeoPoint",
               "latitude": 37.71,
               "longitude": -122.53
             },
             {
               "__type": "GeoPoint",
               "latitude": 30.82,
               "longitude": -122.37
             }
           ]
         }
       }
     })})
connection.connect()
connection.request('GET', '/1/classes/PizzaPlaceObject?%s' % params, '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

Caveats

At the moment there are a couple of things to watch out for:

  1. Each PFObject class may only have one key with a PFGeoPoint object.
  2. Using the $nearSphere constraint will also limit results to within 100 miles.
  3. Points should not equal or exceed the extreme ends of the ranges. Latitude should not be -90.0 or 90.0. Longitude should not be -180.0 or 180.0. Attempting to use GeoPoint's with latitude and/or longitude outside these ranges will cause an error.
Want to contribute to this doc? Edit this section.
Was this section helpful? NO YES Thanks for your feedback, we’re always working to make our docs better.

Push Notification

Push Notifications are a great way to keep your users engaged and informed about your app. You can reach your entire user base quickly and effectively. This guide will help you through the setup process and the general usage of Parse to send push notifications.

If you haven't installed the SDK yet, please head over to the Push QuickStart to get our SDK up and running.

Installations

Uploading Installation Data

An installation object represents an instance of your app being installed on a device. These objects are used to store subscription data for installations which have subscribed to one or more push notification channels. Installations have a flexible schema, except that the special fields below have special type and validation requirements:

Most of the time, installation data is modified by push-related methods in the client SDK. For example, calling subscribeToChannel or unsubscribeFromChannel from the client SDK will create an object for that installation if it doesn't yet exist and update its channels, and calling getSubscribedChannels from the client SDK will read subscription data from that installation's object. The REST methods can be used to mimic these operations. For instance, if you have an iOS device token then you can subscribe it to push notifications by creating an installation object for it with the desired channels list. You can also perform operations which aren't possible through the client SDK, like using a query over installations to find the set of subscribers to a given channel.

Creating an installation object is similar to creating a generic object, but the special installation fields listed above must pass validation. For example, if you have a device token provided by the Apple Push Notification service and would like to subscribe it to the broadcast channel "", you can use the following command:

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "deviceType": "ios",
        "deviceToken": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
        "channels": [
          ""
        ]
      }' \
  https://api.parse.com/1/installations
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/installations', json.dumps({
       "deviceType": "ios",
       "deviceToken": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
       "channels": [
         ""
       ]
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

When the creation is successful, the HTTP response is a 201 Created and the Location header contains the URL for the new installation:

Status: 201 Created
Location: https://api.parse.com/1/installations/mrmBZvsErB

The response body is a JSON object containing the objectId and the createdAt timestamp of the newly-created installation:

{
  "createdAt": "2012-04-28T17:41:09.106Z",
  "objectId": "mrmBZvsErB"
}

When creating Android installation objects containing GCM (Google Cloud Messaging) credentials, you must have at least the following fields in your installation object:

You could create and object with these fields using a command like this:

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "deviceType": "android",
        "pushType": "gcm",
        "deviceToken": "APA91bFMvbrGg4cp3KUV_7dhU1gmwE_...",
        "GCMSenderId": "56712320625545",
        "channels": [
          ""
        ]
      }' \
  https://api.parse.com/1/installations
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/installations', json.dumps({
       "deviceType": "android",
       "pushType": "gcm",
       "deviceToken": "APA91bFMvbrGg4cp3KUV_7dhU1gmwE_...",
       "GCMSenderId": "56712320625545",
       "channels": [
         ""
       ]
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

If you upload Android installations with GCM credentials, then you must also set the GCM API Key associated with this GCM sender ID in your application's push settings.

Retrieving Installations

You can retrieve the contents of an installation object by sending a GET request to the URL returned in the location header when it was created. For example, to retrieve the installation created above:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  https://api.parse.com/1/installations/mrmBZvsErB
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('GET', '/1/installations/mrmBZvsErB', '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

The response body is a JSON object containing all the user-provided fields, plus the createdAt, updatedAt, and objectId fields:

{
  "deviceType": "ios",
  "deviceToken": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
  "channels": [
    ""
  ],
  "createdAt": "2012-04-28T17:41:09.106Z",
  "updatedAt": "2012-04-28T17:41:09.106Z",
  "objectId": "mrmBZvsErB"
}

Updating Installations

Installation objects can be updated by sending a PUT request to the installation URL. For example, to subscribe the installation above to the "foo" push channel:

curl -X PUT \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "deviceType": "ios",
        "deviceToken": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
        "channels": [
          "",
          "foo"
        ]
      }' \
  https://api.parse.com/1/installations/mrmBZvsErB
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('PUT', '/1/installations/mrmBZvsErB', json.dumps({
       "deviceType": "ios",
       "deviceToken": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
       "channels": [
         "",
         "foo"
       ]
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

Querying Installations

You can retrieve multiple installations at once by sending a GET request to the root installations URL. This functionality is not available in the SDKs, so you must authenticate this method using the X-Parse-Master-Key header in your request instead of the X-Parse-REST-API-Key header. Your master key allows you to bypass ACLs and should only be used from within a trusted environment.

Without any URL parameters, a GET request simply lists installations:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-Master-Key: ${MASTER_KEY}" \
  https://api.parse.com/1/installations
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('GET', '/1/installations', '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-Master-Key": "${MASTER_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

The return value is a JSON object that contains a results field with a JSON array that lists the users.

{
  "results": [
    {
      "deviceType": "ios",
      "deviceToken": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
      "channels": [
        ""
      ],
      "createdAt": "2012-04-28T17:41:09.106Z",
      "updatedAt": "2012-04-28T17:41:09.106Z",
      "objectId": "mrmBZvsErB"
    },
    {
      "deviceType": "ios",
      "deviceToken": "fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210",
      "channels": [
        ""
      ],
      "createdAt": "2012-04-30T01:52:57.975Z",
      "updatedAt": "2012-04-30T01:52:57.975Z",
      "objectId": "sGlvypFQcO"
    }
  ]
}

All of the options for queries that work for regular objects also work for installation objects, so check the section on Querying Objects for more details. By doing an array query over channels, for example, you can find the set of devices subscribed to a given push channel.

Deleting Installations

To delete an installation from the Parse Cloud, send a DELETE request to its URL. This functionality is not available in the client SDKs, so you must authenticate this method using the X-Parse-Master-Key header in your request instead of the X-Parse-REST-API-Key header. Your master key allows you to bypass ACLs and should only be used from within a trusted environment. For example:

curl -X DELETE \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-Master-Key: ${MASTER_KEY}" \
  https://api.parse.com/1/installations/mrmBZvsErB
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('DELETE', '/1/installations/mrmBZvsErB', '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-Master-Key": "${MASTER_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

Sending Pushes

There are two ways to send push notifications using Parse: channels and advanced targeting. Channels offer a simple and easy to use model for sending pushes, while advanced targeting offers a more powerful and flexible model. Both are fully compatible with each other and will be covered in this section.

You can view your past push notifications on the Parse.com push console for up to 30 days after creating your push. For pushes scheduled in the future, you can delete the push on the push console as long as no sends have happened yet. After you send the push, the push console shows push analytics graphs.

Using Channels

The simplest way to start sending notifications is using channels. This allows you to use a publisher-subscriber model for sending pushes. Devices start by subscribing to one or more channels, and notifications can later be sent to these subscribers. The channels subscribed to by a given Installation are stored in the channels field of the Installation object.

Subscribing to Channels

A channel is identified by a string that starts with a letter and consists of alphanumeric characters, underscores, and dashes. It doesn't need to be explicitly created before it can be used and each Installation can subscribe to any number of channels at a time.

Subscribing to a channel via the REST API can be done by updating the Installation object. We send a PUT request to the Installation URL and update the channels field. For example, in a baseball score app, we could do:

curl -X PUT \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "channels": [
          "Giants"
        ]
      }' \
  https://api.parse.com/1/installations/mrmBZvsErB
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('PUT', '/1/installations/mrmBZvsErB', json.dumps({
       "channels": [
         "Giants"
       ]
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

Once subscribed to the "Giants" channel, your Installation object should have an updated channels field.

To unsubscribe from a channel you would need to update the channels array and remove the unsubscribed channel.

Sending Pushes to Channels

With the REST API, the following code can be used to alert all subscribers of the "Giants" and "Mets" channels about the results of the game. This will display a notification center alert to iOS users and a system tray notification to Android users.

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "channels": [
          "Giants",
          "Mets"
        ],
        "data": {
          "alert": "The Giants won against the Mets 2-3."
        }
      }' \
  https://api.parse.com/1/push
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/push', json.dumps({
       "channels": [
         "Giants",
         "Mets"
       ],
       "data": {
         "alert": "The Giants won against the Mets 2-3."
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

Using Advanced Targeting

While channels are great for many applications, sometimes you need more precision when targeting the recipients of your pushes. Parse allows you to write a query for any subset of your Installation objects using the querying API and to send them a push.

Since Installation objects are just like any other object stored in Parse, you can save any data you want and even create relationships between Installation objects and your other objects. This allows you to send pushes to a very customized and dynamic segment of your user base.

Saving Installation Data

Storing arbitrary data on an Installation object is done in the same way we store data on any other object on Parse. In our Baseball app, we could allow users to get pushes about game results, scores and injury reports.

curl -X PUT \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "scores": true,
        "gameResults": true,
        "injuryReports": true
      }' \
  https://api.parse.com/1/installations/mrmBZvsErB
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('PUT', '/1/installations/mrmBZvsErB', json.dumps({
       "scores": True,
       "gameResults": True,
       "injuryReports": True
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

You can even create relationships between your Installation objects and other classes saved on Parse. To associate an Installation with a particular user, for example, you can use a pointer to the _User class on the Installation.

curl -X PUT \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "user": {
          "__type": "Pointer",
          "className": "_User",
          "objectId": "vmRZXZ1Dvo"
        }
      }' \
  https://api.parse.com/1/installations/mrmBZvsErB
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('PUT', '/1/installations/mrmBZvsErB', json.dumps({
       "user": {
         "__type": "Pointer",
         "className": "_User",
         "objectId": "vmRZXZ1Dvo"
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

Sending Pushes to Queries

Once you have your data stored on your Installation objects, you can use a query to target a subset of these devices. Installation queries work just like any other Parse query.

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "where": {
          "injuryReports": true
        },
        "data": {
          "alert": "Willie Hayes injured by own pop fly."
        }
      }' \
  https://api.parse.com/1/push
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/push', json.dumps({
       "where": {
         "injuryReports": True
       },
       "data": {
         "alert": "Willie Hayes injured by own pop fly."
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

We can even use channels with our query. To send a push to all subscribers of the "Giants" channel but filtered by those who want score update, we can do the following:

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "where": {
          "channels": "Giants",
          "scores": true
        },
        "data": {
          "alert": "The Giants scored a run! The score is now 2-2."
        }
      }' \
  https://api.parse.com/1/push
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/push', json.dumps({
       "where": {
         "channels": "Giants",
         "scores": True
       },
       "data": {
         "alert": "The Giants scored a run! The score is now 2-2."
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

If we store relationships to other objects in our Installation class, we can also use those in our query. For example, we could send a push notification to all users near a given location like this.

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "where": {
          "user": {
            "$inQuery": {
              "location": {
                "$nearSphere": {
                  "__type": "GeoPoint",
                  "latitude": 30.0,
                  "longitude": -20.0
                },
                "$maxDistanceInMiles": 1.0
              }
            }
          }
        },
        "data": {
          "alert": "Free hotdogs at the Parse concession stand!"
        }
      }' \
  https://api.parse.com/1/push
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/push', json.dumps({
       "where": {
         "user": {
           "$inQuery": {
             "location": {
               "$nearSphere": {
                 "__type": "GeoPoint",
                 "latitude": 30.0,
                 "longitude": -20.0
               },
               "$maxDistanceInMiles": 1.0
             }
           }
         }
       },
       "data": {
         "alert": "Free hotdogs at the Parse concession stand!"
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

An in depth look at the Installation end point can be found in the REST guide.

Sending Options

Push notifications can do more than just send a message. In iOS, pushes can also include the sound to be played, the badge number to display as well as any custom data you wish to send. In Android, it is even possible to specify an Intent to be fired upon receipt of a notification. An expiration date can also be set for the notification in case it is time sensitive.

Customizing your Notifications

If you want to send more than just a message, you can set other fields in the data dictionary. There are some reserved fields that have a special meaning.

For example, to send a notification that increases the current badge number by 1 and plays a custom sound for iOS devices, and displays a particular title for Android users, you can do the following:

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "channels": [
          "Mets"
        ],
        "data": {
          "alert": "The Mets scored! The game is now tied 1-1.",
          "badge": "Increment",
          "sound": "cheering.caf",
          "title": "Mets Score!"
        }
      }' \
  https://api.parse.com/1/push
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/push', json.dumps({
       "channels": [
         "Mets"
       ],
       "data": {
         "alert": "The Mets scored! The game is now tied 1-1.",
         "badge": "Increment",
         "sound": "cheering.caf",
         "title": "Mets Score!"
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

It is also possible to specify your own data in this dictionary. As explained in the Receiving Notifications section for iOS and Android, iOS will give you access to this data only when the user opens your app via the notification and Android will provide you this data in the Intent if one is specified.

```
```python
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/push', json.dumps({
       "channels": [
         "Indians"
       ],
       "data": {
         "action": "com.example.UPDATE_STATUS",
         "alert": "Ricky Vaughn was injured during the game last night!",
         "name": "Vaughn",
         "newsItem": "Man bites dog"
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

Setting an Expiration Date

When a user's device is turned off or not connected to the internet, push notifications cannot be delivered. If you have a time sensitive notification that is not worth delivering late, you can set an expiration date. This avoids needlessly alerting users of information that may no longer be relevant.

There are two parameters provided by Parse to allow setting an expiration date for your notification. The first is expiration_time which takes a date (in ISO 8601 format or Unix epoch time) specifying when Parse should stop trying to send the notification. To expire the notification exactly 1 week from now, you can use the following command.

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "expiration_time": "2015-03-19T22:05:08Z",
        "data": {
          "alert": "Season tickets on sale until March 19, 2015"
        }
      }' \
  https://api.parse.com/1/push
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/push', json.dumps({
       "expiration_time": "2015-03-19T22:05:08Z",
       "data": {
         "alert": "Season tickets on sale until March 19, 2015"
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

Alternatively, you can use the expiration_interval parameter to specify a duration of time before your notification expired. This value is relative to the push_time parameter used to schedule notifications. This means that a push notification scheduled to be sent out in 1 day and an expiration interval of 6 days can be received up to a week from March 16th, 2015.

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "push_time": "2015-03-13T22:05:08Z",
        "expiration_interval": 518400,
        "data": {
          "alert": "Season tickets on sale until March 19, 2015"
        }
      }' \
  https://api.parse.com/1/push
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/push', json.dumps({
       "push_time": "2015-03-13T22:05:08Z",
       "expiration_interval": 518400,
       "data": {
         "alert": "Season tickets on sale until March 19, 2015"
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

Targeting by Platform

If you build a cross platform app, it is possible you may only want to target iOS or Android devices. There are two methods provided to filter which of these devices are targeted. Note that both platforms are targeted by default.

The following examples would send a different notification to Android, iOS, and Windows users.

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "where": {
          "deviceType": "android"
        },
        "data": {
          "alert": "Your suitcase has been filled with tiny robots!"
        }
      }' \
  https://api.parse.com/1/push
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/push', json.dumps({
       "where": {
         "deviceType": "android"
       },
       "data": {
         "alert": "Your suitcase has been filled with tiny robots!"
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result
curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "where": {
          "deviceType": "ios"
        },
        "data": {
          "alert": "Your suitcase has been filled with tiny apples!"
        }
      }' \
  https://api.parse.com/1/push
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/push', json.dumps({
       "where": {
         "deviceType": "ios"
       },
       "data": {
         "alert": "Your suitcase has been filled with tiny apples!"
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result
curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "where": {
          "deviceType": "winrt"
        },
        "data": {
          "alert": "Your suitcase has been filled with tiny glass!"
        }
      }' \
  https://api.parse.com/1/push
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/push', json.dumps({
       "where": {
         "deviceType": "winrt"
       },
       "data": {
         "alert": "Your suitcase has been filled with tiny glass!"
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result
curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "where": {
          "deviceType": "winphone"
        },
        "data": {
          "alert": "Your suitcase is very hip; very metro."
        }
      }' \
  https://api.parse.com/1/push
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/push', json.dumps({
       "where": {
         "deviceType": "winphone"
       },
       "data": {
         "alert": "Your suitcase is very hip; very metro."
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

Scheduling Pushes

You can schedule a push in advance by specifying a push_time. For example, if a user schedules a game reminder for a game on March 19th, 2015 at noon UTC, you can schedule the push notification by sending:

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "where": {
          "user_id": "user_123"
        },
        "push_time": "2015-03-19T12:00:00Z",
        "data": {
          "alert": "You previously created a reminder for the game today"
        }
      }' \
  https://api.parse.com/1/push
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/push', json.dumps({
       "where": {
         "user_id": "user_123"
       },
       "push_time": "2015-03-19T12:00:00Z",
       "data": {
         "alert": "You previously created a reminder for the game today"
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

If you also specify an expiration_interval, it will be calculated from the scheduled push time, not from the time the push is submitted. This means a push scheduled to be sent in a week with an expiration interval of a day will expire 8 days after the request is sent.

The scheduled time cannot be in the past, and can be up to two weeks in the future. It can be an ISO 8601 date with a date, time, and timezone, as in the example above, or it can be a numeric value representing a UNIX epoch time in seconds (UTC). To schedule an alert for 08/22/2015 at noon UTC time, you can set the push_time to either 2015-08-022T12:00:00.000Zor1440226800000`.

Local Push Scheduling

The push_time parameter can schedule a push to be delivered to each device according to its time zone. This technique delivers a push to all Installation objects with a timeZone member when that time zone would match the push time. For example, if an app had a device in timezone America/New_York and another in America/Los_Angeles, the first would receive the push three hours before the latter.

To schedule a push according to each device's local time, the timeZone parameter should be an ISO 8601 date without a time zone, i.e. 2015-03-19T12:00:00. Note that Installations without a timeZone will be excluded from this localized push.

Want to contribute to this doc? Edit this section.
Was this section helpful? NO YES Thanks for your feedback, we’re always working to make our docs better.

Config

Parse Config is a way to configure your applications remotely by storing a single configuration object on Parse. It enables you to add things like feature gating or a simple "Message of the day". To start using Parse Config you need to add a few key/value pairs (parameters) to your app on the Parse Config Dashboard.

After that you will be able to fetch the config on the client by sending a GET request to config URL. Here is a simple example that will fetch the Parse.Config:

curl -X GET \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  https://api.parse.com/1/config
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('GET', '/1/config', '', {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}"
     })
result = json.loads(connection.getresponse().read())
print result

The response body is a JSON object containing all the configuration parameters in the params field.

{
  "params": {
    "welcomeMessage": "Welcome to The Internet!",
    "winningNumber": 42
  }
}
Want to contribute to this doc? Edit this section.
Was this section helpful? NO YES Thanks for your feedback, we’re always working to make our docs better.

Analytics

Parse provides a number of hooks for you to get a glimpse into the ticking heart of your app. We understand that it's important to understand what your app is doing, how frequently, and when.

While this section will cover different ways to instrument your app to best take advantage of Parse's analytics backend, developers using Parse to store and retrieve data can already take advantage of metrics on Parse.

Without having to implement any client-side logic, you can view real-time graphs and breakdowns (by device type, Parse class name, or REST verb) of your API Requests in your app's dashboard and save these graph filters to quickly access just the data you're interested in.

The current server time will be used for all analytics requests. To explicitly set the time associated with a given event, an optional at parameter can be provided in ISO 8601 format.

-d '{
    "at": {
      "__type": "Date",
      "iso": "2015-03-01T15:59:11-07:00"
    }
  }

App-Open Analytics

Our analytics hook allows you to track your application being launched. By making a POST request to our REST API, you'll begin to collect data on when and how often your application is opened.

In the example below, the at parameter is optional. If omitted, the current server time will be used instead.

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
      }' \
  https://api.parse.com/1/events/AppOpened
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/events/AppOpened', json.dumps({
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

Graphs and breakdowns of your statistics are accessible from your app's Dashboard.

Custom Analytics

Parse Analytics also allows you to track free-form events, with a handful of string keys and values. These extra dimensions allow segmentation of your custom events via your app's Dashboard.

Say your app offers search functionality for apartment listings, and you want to track how often the feature is used, with some additional metadata.

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "dimensions": {
          "priceRange": "1000-1500",
          "source": "craigslist",
          "dayType": "weekday"
        }
      }' \
  https://api.parse.com/1/events/Search
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/events/Search', json.dumps({
       "dimensions": {
         "priceRange": "1000-1500",
         "source": "craigslist",
         "dayType": "weekday"
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

Parse Analytics can even be used as a lightweight error tracker — simply invoke the following and you'll have access to an overview of the rate and frequency of errors, broken down by error code, in your application:

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "dimensions": {
          "code": "404"
        }
      }' \
  https://api.parse.com/1/events/Error
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/events/Error', json.dumps({
       "dimensions": {
         "code": "404"
       }
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

Note that Parse currently only stores the first eight dimension pairs per call to /1/events/<eventName>.

Want to contribute to this doc? Edit this section.
Was this section helpful? NO YES Thanks for your feedback, we’re always working to make our docs better.

Cloud Code

Cloud Functions

Cloud Functions can be called using the REST API. For example, to call the Cloud Function named hello:

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{}' \
  https://api.parse.com/1/functions/hello
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/functions/hello', json.dumps({
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-REST-API-Key": "${REST_API_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result

Background Jobs

Similarly, you can trigger a background job from the REST API. For example, to trigger the job named userMigration:

Take a look at the Cloud Code Guide to learn more about Cloud Functions and Background Jobs.
curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-Master-Key: ${MASTER_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"plan":"paid"}' \
  https://api.parse.com/1/jobs/userMigration
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('POST', '/1/jobs/userMigration', json.dumps({
       "plan": "paid"
     }), {
       "X-Parse-Application-Id": "${APPLICATION_ID}",
       "X-Parse-Master-Key": "${MASTER_KEY}",
       "Content-Type": "application/json"
     })
result = json.loads(connection.getresponse().read())
print result
Want to contribute to this doc? Edit this section.
Was this section helpful? NO YES Thanks for your feedback, we’re always working to make our docs better.