Using the Graph API

We cover the basics of Graph API terminology and structure in the Graph API overview. This document goes into more detail about the various operations you can perform with the Graph API.

HTTP/1.1

All data transfers conform to HTTP/1.1, and all endpoints require HTTPS. We have also enabled the includeSubdomains HSTS directive on facebook.com, but this should not adversely affect your Graph API calls.

Host URL

Almost all requests are passed to the graph.facebook.com host URL. The single exception is video uploads, which use graph-video.facebook.com.

Access Tokens

Access tokens allow your app to access the Graph API. They typically perform two functions:

  • they allow your app to access a User's information without requiring the User's password, and
  • they allow us to identify your app, the User who is using your app, and the type of data the User has permitted your app to access.

All Graph API endpoints require an access token of some kind, so each time you access an endpoint, your request must include one.

How Tokens Work

Access tokens conform to the OAuth 2.0 protocol. OAuth 2.0 allows entities such as a User or a Page to authorize tokens. Usually this is done through a web interface. Once authorized, apps can use those tokens to access specific information.

For example, this app is asking a User to give it permission to access the User's photos, videos, and email address:

As you can see, this is a Facebook interface. The User has just used the interface to sign into their account, which has allowed us to authenticate the User. If the User continues, we'll exchange the old token (an App token) for a new one (a User token). The app can then use the new User token to make Graph API requests, but can only access that specific User's photos, videos, and email address.

This is an important attribute of access tokens. The app and User IDs are both encoded in the token itself (among other things), and we use those IDs to keep track of which data the User has permitted the app to access. For example, if you inspected the token after the User granted permission, it would reveal this information:

Since tokens permit access to a User's data, and since they can be used by anyone, they are extremely valuable, so take precautions when using them in your queries. The easiest way to do this is to use Facebook Login to handle your tokens.

Facebook Login

OAuth 2.0 involves a lot of redirects, login prompts, and token exchanging, so to make things easier for you, we created the Facebook Login product. Facebook Login has easy-to-use functions and methods for all of our SDKs which can make working with access tokens much simpler than building your own solution.

To read more about access tokens and Facebook Login, or to learn how to build your own solution, refer to our Facebook Login documentation.

Reading

Nodes

Reading operations almost always begin with a node. A node is an individual object with a unique ID. For example, there are many Page node objects, each with a unique ID, and the Coca-Cola Page is the only one with the ID 820882001277849. To read any node, you query a specific object's ID. So, to read the Coca-Cola Page node you would query its ID:

GET https://graph.facebook.com/v2.11
  /820882001277849

This request would return the following fields (node properties) by default, formatted using JSON:

{
  "name": "Coca-Cola",
  "id": "820882001277849"
}

Edges

Nodes have edges, which usually can return collections of other nodes which are attached to them. To read an edge, you must include both the node ID and the edge name in the path. For example, /page nodes have a /feed edge which can return all Post nodes on a Page. Here's how you could use the edge to get all of the Posts on the Coca-Cola Page:

GET https://graph.facebook.com/v2.11
  /820882001277849
    /feed

The JSON response would look something like this:

{
  "data": [
    {
      "created_time": "2017-12-08T01:08:57+0000",
      "message": "Love this puzzle. One of my four coke puzzles",
      "id": "820882001277849_1805191182846921"
    },
    {
      "created_time": "2017-12-07T20:06:14+0000",
      "message": "You need to add grape as a flavor for Coke in your freestyle machines.",
      "id": "820882001277849_1804966026202770"
    },
    {
      "created_time": "2017-12-07T01:29:12+0000",
      "message": "Plz play the old commercial’s with the polar bears. Would be nice to see them this holiday",
      "id": "820882001277849_1804168469615859"
    }
  ]
}

Notice that the response contains not only the IDs of the Post nodes in the collection, but the created_time and message fields as well. This is common. Most edges will include one or more fields by default.

Fields

Fields are node properties. When you query a node it will return a set of fields by default, as the examples above show. However, you can specify which fields you want returned by using the fields parameter and listing each field. This will override the defaults and return only the fields you specify, and the ID of the object, which is always returned.

For example, the Page node reference indicates which fields you can ask for when reading a Page node. If you wanted to get the about, fan_count, and website fields for the Coca-Cola Page, you could do this:

GET https://graph.facebook.com/v2.11
  /820882001277849
    ?fields=about,fan_count,website

This would return the following response:

{
  "about": "Welcome to the happiest Facebook page on, um, Facebook.",
  "fan_count": 106714402,
  "website": "http://coca-cola.com",
  "id": "820882001277849"
}

Edges, which typically return collections of objects, also return fields about each object in the collection. Let's say you used the /photos edge to get all of the Photo nodes on the Coca-Cola Page:

GET https://graph.facebook.com/v2.11
  /820882001277849
    /photos

This would generate a response that looks similar to this this:

{
  "data": [
    {
      "created_time": "2016-08-23T13:12:10+0000",
      "id": "1308573619175349"
    },
    {
      "created_time": "2016-08-05T22:34:19+0000",
      "id": "1294456907253687"
    },
    {
      "created_time": "2016-04-29T16:17:02+0000",
      "id": "1228552183844160"
    }
  ]
}

As you can see, the /photos edge by default will return a collection of Photo node IDs as well as the created_time property for each photo. Just like with nodes, you can use the fields parameter to specify which fields you want returned for each of the objects returned in the collection.

Let's say you wanted to get the height, width, and link (URL) fields for each Photo node returned by the /photos edge:

GET https://graph.facebook.com/v2.11
  /820882001277849
    /photos
      ?fields=height,width,link

Here's what the response would look like:

{
  "data": [
    {
      "height": 720,
      "width": 720,
      "link": "https://www.facebook.com/CocaColaUnitedStates/photos/a.820887414610641.1073741825.820882001277849/1308573619175349/?type=3",
      "id": "1308573619175349"
    },
    {
      "height": 720,
      "width": 720,
      "link": "https://www.facebook.com/CocaColaUnitedStates/photos/a.820887414610641.1073741825.820882001277849/1294456907253687/?type=3",
      "id": "1294456907253687"
    },
    {
      "height": 180,
      "width": 180,
      "link": "https://www.facebook.com/CocaColaUnitedStates/photos/a.820887414610641.1073741825.820882001277849/1228552183844160/?type=3",
      "id": "1228552183844160"
    }
  ]
}

Note that you can specify an edge with the fields parameter as well, which is useful when you are using field expansion.

Field Expansion

If you happened to test the GET /page/photos query above in the Graphi API Explorer, you probably noticed that the request returned more than three objects and also paginated the results. This is common for most edges. We'll cover traversing results soon, but for now let's look at field expansion, which allows you to not only perform nested queries, but also limit and order the results.

Limiting Results

Limiting allows you to control the number of objects returned in each set of paginated results. To limit results, add a .limit() argument to any field or edge.

For example, performing a GET request on the Coca-Cola Page's /feed edge may return hundreds of Posts. You can limit the number of Posts returned for each page of results by doing this:

GET https://graph.facebook.com/v2.11
  /820882001277849
    ?fields=feed.limit(3)

This returns all of the Posts on the Coca-Cola Page, but limits the number of objects in each page of results to three. Notice that instead of specifying the Feed edge in the path URL (/page/feed), you specify it in the fields parameter (?fields=feed), which allows you to append the .limit(3) argument.

Here are the query results:

{
  "feed": {
    "data": [
      {
        "created_time": "2017-12-12T01:24:21+0000",
        "message": "This picture of my grandson with Santa screams Coca Cola",
        "id": "820882001277849_1809387339093972"
      },
      {
        "created_time": "2017-12-11T23:40:17+0000",
        "message": ":)",
        "id": "820882001277849_1809316002434439"
      },
      {
        "created_time": "2017-12-11T23:31:38+0000",
        "message": "Thought you might enjoy this.  My horse loves Coke!",
        "id": "820882001277849_1809310929101613"
      }
    ],
    "paging": {
      "cursors": {
        "before": "Q2c4U1pXNTBYM0YxWlhKNVgzTjBiM0o1WDJsa0R5UTRNakE0T0RJd01ERXlOemM0TkRrNkxUVXdPRE16TXpVM01EQXpNVFUwTkRRME5Ua1BER0ZA3YVY5emRHOXllVjlwWkE4ZA09ESXdPRGd5TURBeE1qYzNPRFE1WHpFNE1Ea3pPRGN6TXprd09UTTVOeklQQkhScGJXVUdXaTh2eFFFPQZDZD",
        "after": "Q2c4U1pXNTBYM0YxWlhKNVgzTjBiM0o1WDJsa0R5TTRNakE0T0RJd01ERXlOemM0TkRrNk1UTTJORE01T0RVNU1UZAzVPRGMyTnpFNE1BOE1ZAWEJwWDNOMGIzSjVYMmxrRHlBNE1qQTRPREl3TURFeU56YzRORGxmTVRnd09USXdOamsxTlRjM09EWTNOdzhFZAEdsdFpRWmFMdk9HQVE9PQZDZD"
      },
      "next": "https://graph.intern.facebook.com/v2.11/820882001277849/feed?access_token=valid_token_goes_here"
    }
  },
  "id": "820882001277849"
}

As you can see, only three objects appear in this page of paginated results, but the response included a next field and URL which you can use to fetch the next page.

Ordering Results

You can order results based on object creation time. To do this, use a .order() argument with one of the following values on either a field or edge.

  • chronological — orders results with the oldest created objects first.
  • reverse_chronological — orders results with the newest created objects first.

For example, let's get all of the Comments on one of the Coca-Cola Page's video Posts (1809938745705498), order the results chronologically (oldest first), and limit the number of objects per paginated result to three:

GET https://graph.facebook.com/v2.11
  /1809938745705498
    ?fields=comments.order(chronological).limit(3)

Again, notice that in order to use an argument on an edge you have to specify the edge in the fields parameter. And as you can see, you can combine .limit() and .order() arguments on a single field or edge.

Here are the results:

{
  "comments": {
    "data": [
      {
        "created_time": "2017-12-12T14:12:20+0000",
        "message": ":) :) :)",
        "id": "1809938745705498_1809939942372045"
      },
      {
        "created_time": "2017-12-12T14:14:03+0000",
        "message": "seasons greetings!",
        "id": "1809938745705498_1809941802371859"
      },
      {
        "created_time": "2017-12-12T14:14:11+0000",
        "message": "My bestie <3",
        "id": "1809938745705498_1809941879038518"
      }
    ],
    "paging": {
      "cursors": {
        "before": "WTI5dGJXVnVkRjlqZAFhKemIzSTZANVGd3T1Rrek9UZAzROVGN3TlRNNE5Eb3hOVEV6TURnM09UTTIZD",
        "after": "WTI5dGJXVnVkRjlqZAFhKemIzSTZANVGd4TURBd09UazROVFk1T0RNM05Eb3hOVEV6TURreU5qQXoZD"
      },
      "next": "https://graph.intern.facebook.com/v2.11/1809938745705498/comments?access_token=valid_token_goes_here"
    }
  },
  "id": "1809938745705498"
}

Publishing

Most edges allow you to publish objects to a collection on a node. You can do this by using a POST request on the node's edge. For example, you can publish a Comment on a Photo by using the Photo node's /comments edge:

POST https://graph.facebook.com
  /1809938745705498
    /comments
      ?message=Awesome!

If successful, most edges will return the ID of the object that you just published, which is often a combination of the ID the object was published on and a new ID string:

{
  "id": "1809938745705498_1810399758992730"
}

Publishing typically requires additional permissions, so please refer to each edge's reference documentation to determine which permissions they require.

The access token used to publish the object may affect the appearance of the object. If a Page access token is used, it will appear as if the Page posted the object, while a User access token will cause the object to appear as if posted by a person.

Many edges also support advanced features, such as Read-After-Write, which allows you to immediately read a newly published object, and Batch Publishing, which allows you to chain together multiple publishing operations.

Updating

You can perform update operations on an existing node by using POST requests. For example, to update the message field on an existing Comment, you can do this:

POST https://graph.facebook.com
  /1809938745705498_1810399758992730
    ?message=Happy%20Holidays!

If successful, the node will return a success field and a value of true:

{
  "success": true
}

Like publishing operations, update operations require additional permissions which will be listed in each node's reference documentation. And, just like most edges, many nodes support Read-After-Write.

Deleting

You can typically delete a node by using a DELETE operation it:

DELETE https://graph.facebook.com
  /1809938745705498_1810399758992730

If successful, the node will return a success field and a value of true:

{
  "success": true
}

Usually you can only delete nodes that you created, but check each node's reference guide to see requirements for delete operations.

To support clients that do not support all HTTP methods, you can send a POST request to the node and include the method=delete parameter and value to override the HTTP method:

POST https://graph.facebook.com
  /1809938745705498_1810399758992730
    ?method=delete

Traversing Paged Results

When you make an API request to a node or edge, you usually don't receive all of the results of that request in a single response. This is because some responses could contain thousands of objects so most responses are paginated by default.

Cursor-based Pagination

Cursor-based pagination is the most efficient method of paging and should always be used where possible. A cursor refers to a random string of characters which marks a specific item in a list of data. Unless this item is deleted, the cursor will always point to the same part of the list, but will be invalidated if an item is removed. Therefore, your app shouldn't store cursors and assume that they will be valid in the future.

When reading an edge that supports cursor pagination, you will see the following JSON response:

{
  "data": [
     ... Endpoint data is here
  ],
  "paging": {
    "cursors": {
      "after": "MTAxNTExOTQ1MjAwNzI5NDE=",
      "before": "NDMyNzQyODI3OTQw"
    },
    "previous": "https://graph.facebook.com/me/albums?limit=25&before=NDMyNzQyODI3OTQw"
    "next": "https://graph.facebook.com/me/albums?limit=25&after=MTAxNTExOTQ1MjAwNzI5NDE="
  }
}

A cursor-paginated edge supports the following parameters:

  • before : This is the cursor that points to the start of the page of data that has been returned.
  • after : This is the cursor that points to the end of the page of data that has been returned.
  • limit : This is the maximum number of objects that may be returned. A query may return fewer than the value of limit due to filtering. Do not depend on the number of results being fewer than the limit value to indicate your query reached the end of the list of data, use the absence of next instead as described below. For example, if you set limit to 10 and 9 results are returned, there may be more data available, but one item was removed due to privacy filtering. Some edges may also have a maximum on the limit value for performance reasons. In all cases, the API returns the correct pagination links.
  • next : The Graph API endpoint that will return the next page of data. If not included, this is the last page of data. Due to how pagination works with visibility and privacy, it is possible that a page may be empty but contain a 'next' paging link. Stop paging when the 'next' link no longer appears.
  • previous : The Graph API endpoint that will return the previous page of data. If not included, this is the first page of data.

Don't store cursors. Cursors can quickly become invalid if items are added or deleted.

Time-based Pagination

Time pagination is used to navigate through results data using Unix timestamps which point to specific times in a list of data.

When using an endpoint that uses time-based pagination, you will see the following JSON response:

{
  "data": [
     ... Endpoint data is here
  ],
  "paging": {
    "previous": "https://graph.facebook.com/me/feed?limit=25&since=1364849754",
    "next": "https://graph.facebook.com/me/feed?limit=25&until=1364587774"
  }
}

A time-paginated edge supports the following parameters:

  • until : A Unix timestamp or strtotime data value that points to the end of the range of time-based data.
  • since : A Unix timestamp or strtotime data value that points to the start of the range of time-based data.
  • limit : This is the maximum number of objects that may be returned. A query may return fewer than the value of limit due to filtering. Do not depend on the number of results being fewer than the limit value to indicate your query reached the end of the list of data, use the absence of next instead as described below. For example, if you set limit to 10 and 9 results are returned, there may be more data available, but one item was removed due to privacy filtering. Some edges may also have a maximum on the limit value for performance reasons. In all cases, the API returns the correct pagination links.
  • next : The Graph API endpoint that will return the next page of data.
  • previous : The Graph API endpoint that will return the previous page of data.

For consistent results, specify both since and until parameters. Also, it is recommended that the time difference is a maximum of 6 months.

Offset-based Pagination

Offset pagination can be used when you do not care about chronology and just want a specific number of objects returned. This should only be used if the edge does not support cursor or time-based pagination.

An offset-paginated edge supports the following parameters:

  • offset : This offsets the start of each page by the number specified.
  • limit : This is the maximum number of objects that may be returned. A query may return fewer than the value of limit due to filtering. Do not depend on the number of results being fewer than the limit value to indicate your query reached the end of the list of data, use the absence of next instead as described below. For example, if you set limit to 10 and 9 results are returned, there may be more data available, but one item was removed due to privacy filtering. Some edges may also have a maximum on the limit value for performance reasons. In all cases, the API returns the correct pagination links.
  • next : The Graph API endpoint that will return the next page of data. If not included, this is the last page of data. Due to how pagination works with visibility and privacy, it is possible that a page may be empty but contain a 'next' paging link. Stop paging when the 'next' link no longer appears.
  • previous : The Graph API endpoint that will return the previous page of data. If not included, this is the first page of data.

Note that if new objects are added to the list of items being paged, the contents of each offset-based page will change.

Offset based pagination is not supported for all API calls. To get consistent results, we recommend you to paginate using the previous/next links we return in the response.