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.

How to Get an Access Token

After you've implemented one of our Facebook Login SDKs, you can use its methods to get an access token with your needed permission. If the User grants your app permission, the API will respond with an access token, which you can capture using an SDK method.

Sample Code

LoginManager.getInstance().logInWithPublishPermissions(
    fragmentOrActivity,
    Arrays.asList("user_birthday"));
FBSDKLoginManager *loginManager = [[FBSDKLoginManager alloc] init];
  [loginManager logInWithPublishPermissions:@[@"user_birthday"]
                         fromViewController:self
                                    handler:^(FBSDKLoginManagerLoginResult *result, NSError
FB.login(function(response) {
  console.log(response);
}, {scope: 'user_birthday'});
If you want to confirm that the User has granted your app the user_birthday permission, you can perform a GET operation on the /{user-id}/permissions edge. Assuming the User granted the permission, the API response would look like this:

Sample Response

{
  "data": [
    {
      "permission":"user_birthday",
      "status":"granted"
    }
  ]
}

Note: Fastest way to get your FBID, permissions, and a User access token to try the following examples would be to visit the Graph Explorer tool and click Get Token, Get User Access Token where you can select and approve permissions, then Submit.

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 User node objects, each with a unique ID representing a person on Facebook. To read a node, you query a specific object's ID. So, to read your User node you would query its ID:

curl -i -X GET \
 "https://graph.facebook.com/{your-user-id}
   ?fields=id,name
   &access_token={your-user-access-token}"
GraphRequest request = GraphRequest.newMeRequest(
  accessToken,
  new GraphRequest.GraphJSONObjectCallback() {
    @Override
    public void onCompleted(JSONObject object, GraphResponse response) {
      // Insert your code here
    }
});

Bundle parameters = new Bundle();
parameters.putString("fields", "id,name");
request.setParameters(parameters);
request.executeAsync();
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc]
    initWithGraphPath:@"/me"
           parameters:@{ @"fields": @"id,name",}
           HTTPMethod:@"GET"];
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
    // Insert your code here
}];
FB.api(
  '/me',
  'GET',
  {"fields":"id,name"},
  function(response) {
      // Insert your code here
  }
);
try {
  // Returns a `FacebookFacebookResponse` object
  $response = $fb->get(
    '/me',
    '{access-token}'
  );
} catch(FacebookExceptionsFacebookResponseException $e) {
  echo 'Graph returned an error: ' . $e->getMessage();
  exit;
} catch(FacebookExceptionsFacebookSDKException $e) {
  echo 'Facebook SDK returned an error: ' . $e->getMessage();
  exit;
}
$graphNode = $response->getGraphNode();

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

{
  "name": "Your Name",
  "id": "your-user-id"
}

/me

The /me node is a special endpoint that translates to the user_id of the person (or the page_id of the Facebook Page) whose access token is currently being used to make the API calls. If you had a user access token, you could retrieve all of a user's photos by using:

GET graph.facebook.com
  /me/photos

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, /user nodes have a /feed edge which can return all Post nodes on a User. You'll need to get a new access token and select user_posts permissions during the Get access token flow. Here's how you could use the edge to get all your Posts:

curl -i -X GET \
  "https://graph.facebook.com/{your-user-id}/feed
    ?access_token={your-user-access-token}"
GraphRequest request = GraphRequest.newGraphPathRequest(
  accessToken,
  "/me/feed",
  new GraphRequest.Callback() {
    @Override
    public void onCompleted(GraphResponse response) {
      // Insert your code here
    }
});

request.executeAsync();
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc]
    initWithGraphPath:@"/me/feed"
           parameters:nil
           HTTPMethod:@"GET"];
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
    // Insert your code here
}];
FB.api(
  '/me/feed',
  'GET',
  {},
  function(response) {
      // Insert your code here
  }
);
try {
  // Returns a `FacebookFacebookResponse` object
  $response = $fb->get(
    '/me/feed',
    '{access-token}'
  );
} catch(FacebookExceptionsFacebookResponseException $e) {
  echo 'Graph returned an error: ' . $e->getMessage();
  exit;
} catch(FacebookExceptionsFacebookSDKException $e) {
  echo 'Facebook SDK returned an error: ' . $e->getMessage();
  exit;
}
$graphNode = $response->getGraphNode();

The JSON response would look something like this:

{
  "data": [
    {
      "created_time": "2017-12-08T01:08:57+0000",
      "message": "Love this puzzle. One of my favorite puzzles",
      "id": "post-id"
    },
    {
      "created_time": "2017-12-07T20:06:14+0000",
      "message": "You need to add grape as a flavor.",
      "id": "post-id"
    }
  ]
}

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 User node reference indicates which fields you can ask for when reading a User node. If you wanted to get your birthday, hometown, and email fields, you'll need to get a new access token with user_birthday, email, and user_hometown permissions during the Get access token flow and try this:

curl -i -X GET \
  "https://graph.facebook.com/{your-user-id}
    ?fields=birthday,email,hometown
    &access_token={your-user-access-token}"
GraphRequest request = GraphRequest.newGraphPath
        
        Request(
  accessToken,
  new GraphRequest.GraphJSONObjectCallback() {
    @Override
    public void onCompleted(JSONObject object, GraphResponse response) {
      // Insert your code here
    }
});

Bundle parameters = new Bundle();
parameters.putString("fields", "birthday,email,hometown");
request.setParameters(parameters);
request.executeAsync();
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc]
    initWithGraphPath:@"/{your-user-id}"
           parameters:@{ @"fields": @"birthday,email,hometown",}
           HTTPMethod:@"GET"];
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
    // Insert your code here
}];
FB.api(
  '/{your-user-id}',
  'GET',
  {"fields":"birthday,email,hometown"},
  function(response) {
      // Insert your code here
  }
);
try {
  // Returns a `FacebookFacebookResponse` object
  $response = $fb->get(
    '/{your-user-id}',
    array (
      'fields' => 'birthday','email','hometown'
    ),
    '{access-token}'
  );
} catch(FacebookExceptionsFacebookResponseException $e) {
  echo 'Graph returned an error: ' . $e->getMessage();
  exit;
} catch(FacebookExceptionsFacebookSDKException $e) {
  echo 'Facebook SDK returned an error: ' . $e->getMessage();
  exit;
}
$graphNode = $response->getGraphNode();

This would return the following response:

{
  "hometown": "Your, Hometown"
  "birthday": "01/01/1985",
  "email": "your-email@email.addresss.com",
  "id": "{your-user-id}"
}

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 from your timeline:

curl -i -X GET \
  "https://graph.facebook.com/{your-user-id}/photos
    ?access_token={your-user-access-token}"
GraphRequest request = GraphRequest.newGraphPathRequest(
  accessToken,
  "/{your-user-id}/photos",
  new GraphRequest.Callback() {
    @Override
    public void onCompleted(GraphResponse response) {
      // Insert your code here
    }
});

request.executeAsync();
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc]
    initWithGraphPath:@"/{your-user-id}/photos"
           parameters:nil
           HTTPMethod:@"GET"];
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
    // Insert your code here
}];
FB.api(
  '/{your-user-id}/photos',
  'GET',
  {},
  function(response) {
      // Insert your code here
  }
);
try {
  // Returns a `FacebookFacebookResponse` object
  $response = $fb->get(
    '/{your-user-id}/photos',
    '{access-token}'
  );
} catch(FacebookExceptionsFacebookResponseException $e) {
  echo 'Graph returned an error: ' . $e->getMessage();
  exit;
} catch(FacebookExceptionsFacebookSDKException $e) {
  echo 'Facebook SDK returned an error: ' . $e->getMessage();
  exit;
}
$graphNode = $response->getGraphNode();

This would generate a response that looks similar to this:

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

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, and width fields for each Photo node returned by the /photos edge:

curl -i -X GET \
  "https://graph.facebook.com/{your-user-id}/photos
    ?fields=height,width
    &access_token={your-user-access-token}"
GraphRequest request = GraphRequest.newGraphPathRequest(
  accessToken,
  "/{your-user-id}/photos",
  new GraphRequest.Callback() {
    @Override
    public void onCompleted(GraphResponse response) {
      // Insert your code here
    }
});

Bundle parameters = new Bundle();
parameters.putString("fields", "height,width");
request.setParameters(parameters);
request.executeAsync();
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc]
    initWithGraphPath:@"/{your-user-id}/photos"
           parameters:@{ @"fields": @"height,width",}
           HTTPMethod:@"GET"];
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
    // Insert your code here
}];
FB.api(
  '/{your-user-id}/photos',
  'GET',
  {"fields":"height,width"},
  function(response) {
      // Insert your code here
  }
);
try {
  // Returns a `FacebookFacebookResponse` object
  $response = $fb->get(
    '/{your-user-id}/photos',
    array (
      'fields' => 'height','width'
    )
    '{access-token}'
  );
} catch(FacebookExceptionsFacebookResponseException $e) {
  echo 'Graph returned an error: ' . $e->getMessage();
  exit;
} catch(FacebookExceptionsFacebookSDKException $e) {
  echo 'Facebook SDK returned an error: ' . $e->getMessage();
  exit;
}
$graphNode = $response->getGraphNode();

Here's what the response would look like:

{
  "data": [
    {
      "height": 720,
      "width": 720,
      "id": "1308573619175349"        // Photo ID
    },
    {
      "height": 720,
      "width": 720,
      "id": "1294456907253687"        // Photo ID
    },
    {
      "height": 180,
      "width": 180,
      "id": "1228552183844160"        // Photo ID
    }
  ]
}

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 Graph 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 your /feed edge may return hundreds of Posts. You can limit the number of Posts returned for each page of results by doing this:

curl -i -X GET \
  "https://graph.facebook.com/{your-user-id}
    ?fields=feed.limit(3)
    &access_token={your-access-token}"
try {
  // Returns a `FacebookFacebookResponse` object
  $response = $fb->get(
    '/{your-user-id}',
    '{access-token}'
  );
} catch(FacebookExceptionsFacebookResponseException $e) {
  echo 'Graph returned an error: ' . $e->getMessage();
  exit;
} catch(FacebookExceptionsFacebookSDKException $e) {
  echo 'Facebook SDK returned an error: ' . $e->getMessage();
  exit;
}
$graphNode = $response->getGraphNode();
try {
  // Returns a `FacebookFacebookResponse` object
  $response = $fb->get(
    '/{your-user-id}',
    '{access-token}'
  );
} catch(FacebookExceptionsFacebookResponseException $e) {
  echo 'Graph returned an error: ' . $e->getMessage();
  exit;
} catch(FacebookExceptionsFacebookSDKException $e) {
  echo 'Facebook SDK returned an error: ' . $e->getMessage();
  exit;
}
$graphNode = $response->getGraphNode();
try {
  // Returns a `FacebookFacebookResponse` object
  $response = $fb->get(
    '/{your-user-id}',
    '{access-token}'
  );
} catch(FacebookExceptionsFacebookResponseException $e) {
  echo 'Graph returned an error: ' . $e->getMessage();
  exit;
} catch(FacebookExceptionsFacebookSDKException $e) {
  echo 'Facebook SDK returned an error: ' . $e->getMessage();
  exit;
}
$graphNode = $response->getGraphNode();
try {
  // Returns a `FacebookFacebookResponse` object
  $response = $fb->get(
    '/{your-user-id}',
    array (
      'fields' => 'feed.limit(3)' 
    )
    '{access-token}'
  );
} catch(FacebookExceptionsFacebookResponseException $e) {
  echo 'Graph returned an error: ' . $e->getMessage();
  exit;
} catch(FacebookExceptionsFacebookSDKException $e) {
  echo 'Facebook SDK returned an error: ' . $e->getMessage();
  exit;
}
$graphNode = $response->getGraphNode();

This returns all of the Posts on your User node, 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 (/user/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",
        "id": "{your-user-id}_1809387339093972"       // Post ID
      },
      {
        "created_time": "2017-12-11T23:40:17+0000",
        "message": ":)",
        "id": "{your-user-id}_1809316002434439"       // Post ID
      },
      {
        "created_time": "2017-12-11T23:31:38+0000",
        "message": "Thought you might enjoy this.",
        "id": "{your-user-id}_1809310929101613"       // Post ID
      }
    ],
    "paging": {
      "previous": "https://graph.facebook.com/v3.2/{your-user-id}/feed?format=json&limit=3&since=1542820440&access_token={your-user-access-token}&__paging_token=enc_AdCgj6RSGWTYV7EXj2cFlOWJjbZCq8oI3ogIpLrxPCVK3U8Kad0EgsZA2vri3YKIwl71XGRDJz9C8TgqMeyiu8U5CD&__previous=1",
      "next": "https://graph.facebook.com/v3.2/{your-user-id}/feed?format=json&limit=3&access_token={your-user-access-token}&until=1542583212&__paging_token=enc_AdDLmzUgWiLo6oHGCI53S5begiKOfNZBY0affrLMWgheBzfwMA7XSKmgjyNbuZBIptdXc18j1Se0Dm7vEsePh1SoM3"
    }
  },
  "id": "{your-user-id}"
}

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. Note: Notice that the Post ID is a combination of the ID the object was published on, in this case the User node, and a new ID string.

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 your Posts, order the results chronologically (oldest first), and limit the number of objects per paginated result to three:

curl -i -X GET \
  "https://graph.facebook.com/{your-user-id}
    ?fields=feed.order(chronological).limit(3)
    &access_token={your-user-access-token}"
GraphRequest request = GraphRequest.newGraphPathRequest(
  accessToken,
  "/{your-user-id}",
  new GraphRequest.Callback() {
    @Override
    public void onCompleted(GraphResponse response) {
      // Insert your code here
    }
});

Bundle parameters = new Bundle();
parameters.putString("fields", "feed.order(chronological).limit(3)");
request.setParameters(parameters);
request.executeAsync();
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc]
    initWithGraphPath:@"/{your-user-id}"
           parameters:@{ @"fields": @"feed.order(chronological).limit(3)",}
           HTTPMethod:@"GET"];
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
    // Insert your code here
}];
FB.api(
  '/{your-user-id}',
  'GET',
  {"fields":"feed.order(chronological).limit(3)"},
  function(response) {
      // Insert your code here
  }
);
try {
  // Returns a `FacebookFacebookResponse` object
  $response = $fb->get(
    '/{your-user-id}',
    '{access-token}'
  );
} catch(FacebookExceptionsFacebookResponseException $e) {
  echo 'Graph returned an error: ' . $e->getMessage();
  exit;
} catch(FacebookExceptionsFacebookSDKException $e) {
  echo 'Facebook SDK returned an error: ' . $e->getMessage();
  exit;
}
$graphNode = $response->getGraphNode();

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:

{
  "feed": {
    "data": [
      {
        "created_time": "2017-12-12T01:24:21+0000",
        "message": "This picture of my grandson with Santa",
        "id": "{your-user-id}_1809387339093972"       // Post ID
      },
      {
        "created_time": "2017-12-11T23:40:17+0000",
        "message": ":)",
        "id": "{your-user-id}_1809316002434439"       // Post ID
      },
      {
        "created_time": "2017-12-11T23:31:38+0000",
        "message": "Thought you might enjoy this.",
        "id": "{your-user-id}_1809310929101613"       // Post ID
      }
    ],
    "paging": {
      "previous": "https://graph.facebook.com/v3.2/{your-user-id}/feed?format=json&limit=3&since=1542820440&access_token={your-user-access-token}&__paging_token=enc_AdCgj6RSGWTYV7EXj2cFlOWJjbZCq8oI3ogIpLrxPCVK3U8Kad0EgsZA2vri3YKIwl71XGRDJz9C8TgqMeyiu8U5CD&__previous=1",
      "next": "https://graph.facebook.com/v3.2/{your-user-id}/feed?format=json&limit=3&access_token={your-user-access-token}&until=1542583212&__paging_token=enc_AdDLmzUgWiLo6oHGCI53S5begiKOfNZBY0affrLMWgheBzfwMA7XSKmgjyNbuZBIptdXc18j1Se0Dm7vEsePh1SoM3"
    }
  },
  "id": "{your-user-id}"
}

Publishing

You can only publish to a Page and only with a Page access token of a Page you own or admin. The manage_pages and publish_pages permissions are required and the Page shows as the author of the Post. For all other publishing, use Sharing to allow people to post to Facebook from your app.

To publish to a Page, use a POST request on the Page node's feed edge:

curl -i -X POST \
  "https://graph.facebook.com/{your-page-id}/feed
    ?message=Awesome!
    &access_token={your-page-access-token}"
GraphRequest request = GraphRequest.newPostRequest(
  accessToken,
  "/{your-page-id}/feed",
  new JSONObject("{\"message\":\"Awesome!\"}"),
  new GraphRequest.Callback() {
    @Override
    public void onCompleted(GraphResponse response) {
      // Insert your code here
    }
});
request.executeAsync();
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc]
    initWithGraphPath:@"/{your-page-id}/feed"
           parameters:@{ @"message": @"Awesome!",}
           HTTPMethod:@"POST"];
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
    // Insert your code here
}];
FB.api(
  '/{your-page-id}/feed',
  'POST',
  {"message":"Awesome!"},
  function(response) {
      // Insert your code here
  }
);
try {
  // Returns a `FacebookFacebookResponse` object
  $response = $fb->post(
    '/{your-page-id}/feed',
    array (
      'message' => 'Awesome!'
    ),
    '{access-token}'
  );
} catch(FacebookExceptionsFacebookResponseException $e) {
  echo 'Graph returned an error: ' . $e->getMessage();
  exit;
} catch(FacebookExceptionsFacebookSDKException $e) {
  echo 'Facebook SDK returned an error: ' . $e->getMessage();
  exit;
}
$graphNode = $response->getGraphNode();

If successful, 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": "{your-page-id}_1810399758992730"      // Post ID
}

Many edges 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:

curl -i -X POST \
  "https://graph.facebook.com/{your-page-post-id}
    ?message=Happy%20Holidays!
    &access_token={your-page-access-token}"
GraphRequest request = GraphRequest.newPostRequest(
  accessToken,
  "/{your-page-post-id}",
  new JSONObject("{\"message\":\"It does work\"}"),
  new GraphRequest.Callback() {
    @Override
    public void onCompleted(GraphResponse response) {
      // Insert your code here
    }
});
request.executeAsync();
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc]
    initWithGraphPath:@"/{your-page-post-id}"
           parameters:@{ @"message": @"It does work",}
           HTTPMethod:@"POST"];
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
    // Insert your code here
}];
FB.api(
  '/{your-page-post-id}',
  'POST',
  {"message":"It does work"},
  function(response) {
      // Insert your code here
  }
);
try {
  // Returns a `FacebookFacebookResponse` object
  $response = $fb->post(
    '/{your-page-post-id}',
    array (
      'message' => 'It does work'
    ),
    '{access-token}'
  );
} catch(FacebookExceptionsFacebookResponseException $e) {
  echo 'Graph returned an error: ' . $e->getMessage();
  exit;
} catch(FacebookExceptionsFacebookSDKException $e) {
  echo 'Facebook SDK returned an error: ' . $e->getMessage();
  exit;
}
$graphNode = $response->getGraphNode();

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:

curl -i -X DELETE \
  "https://graph.facebook.com/{your-page-post-id}
    ?access_token={your-page-access-token}"
Bundle parameters = new Bundle();

GraphRequest request = new GraphRequest(
  accessToken,
  "/{page-post-id}",
  parameters,
  HttpMethod.DELETE,
  new GraphRequest.Callback() {
    @Override
    public void onCompleted(GraphResponse response) {
      // Insert your code here
    }
});

request.executeAsync();
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc]
    initWithGraphPath:@"/{page-post-id}"
           parameters:nil
           HTTPMethod:@"DELETE"];
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
    // Insert your code here
}];
FB.api(
  '/{page-post-id}',
  'DELETE',
  {},
  function(response) {
      // Insert your code here
  }
);
try {
  // Returns a `FacebookFacebookResponse` object
  $response = $fb->delete(
    '/{page-post-id}',
    array (),
    '{access-token}'
  );
} catch(FacebookExceptionsFacebookResponseException $e) {
  echo 'Graph returned an error: ' . $e->getMessage();
  exit;
} catch(FacebookExceptionsFacebookSDKException $e) {
  echo 'Facebook SDK returned an error: ' . $e->getMessage();
  exit;
}
$graphNode = $response->getGraphNode();

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

{
  "success": true
}

You can also send a POST request to the node and include the method=delete parameter and value to override the HTTP method:

curl -i -X POST \
  "https://graph.facebook.com/{comment-id}
    ?method=delete
    &access_token={access-token}"

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

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/{your-user-id}/albums?limit=25&before=NDMyNzQyODI3OTQw"
    "next": "https://graph.facebook.com/{your-user-id}/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/{your-user-id}/feed?limit=25&since=1364849754",
    "next": "https://graph.facebook.com/{your-user-id}/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.

For objects that have a large number of items returned, such as comments which can number in the tens of thousands, you may encounter limits while paging. The API will return an error when your app has reached the cursor limit:

{
  "error": {
    "message": "(#100) The After Cursor specified exceeds the max limit supported by this endpoint",
    "type": "OAuthException",
    "code": 100
  }
}

Next Steps

Now that you are more familiar with the Graph API visit our Graph Explorer Tool Guide to explore the Graph without writing code, Common Uses to view the most common tasks performed, and the SDKs available.