Asynchronous and Batch Requests

Use asynchronous requests to create ads and send numerous ads requests without having to block. Either specify a URL to call after requests complete or check the status of the request. See Ad, Reference.

The most efficient way to manage ads is via batched requests. Use it to perform some of the more common requests.

Asynchronous Requests

For example, get the status of the asynchronous request set:

use FacebookAds\Object\AdAsyncRequestSet;
use FacebookAds\Object\Fields\AdAsyncRequestSetFields;

$request_set = new AdAsyncRequestSet(<REQUEST_SET_ID>);
$request_set->read(array(
  AdAsyncRequestSetFields::NAME,
  AdAsyncRequestSetFields::SUCCESS_COUNT,
  AdAsyncRequestSetFields::ERROR_COUNT,
  AdAsyncRequestSetFields::IS_COMPLETED,
));
from facebookads.adobjects.adasyncrequestset import AdAsyncRequestSet

request_set = AdAsyncRequestSet(<REQUEST_SET_ID>)
request_set.remote_read(fields=[
    AdAsyncRequestSet.Field.name,
    AdAsyncRequestSet.Field.success_count,
    AdAsyncRequestSet.Field.error_count,
    AdAsyncRequestSet.Field.is_completed,
])
curl -G \
  -d 'fields=name,success_count,error_count,is_completed' \
  -d 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.11/<REQUEST_SET_ID>

This returns the overall status for the async request set as a JSON object. Not all fields are appear by default. If you want your query to include non-default fields, specify them in fields, such as fields=id,owner_id,name,total_count,success_count,error_count,is_completed.

Name Type Description Shown by default

id

int

The id of current async request set

yes

owner_id

int

Which object owns this async request set. For async requests on ads, owner_id is the account id.

yes

name

string

Name of this async request set

yes

is_completed

bool

Async requests in this set complete

yes

total_count

int

Total requests count of this request set

no

initial_count

int

Number of requests not yet served

no

in_progress_count

int

Number of requests in progress

no

success_count

int

Number of requests finished and successful

no

error_count

int

Number of requests finished and failed

no

canceled_count

int

Number of requests canceled by user

no

notification_uri

string

Notification URI for this async request set.

no

notification_mode

string

Way to receive notification. Valid values include:


OFF – No notifications


ON_COMPLETE – Send notification when whole set finished.

no

After you get the overall status of the async request set, get details of each request:

use FacebookAds\Object\AdAsyncRequestSet;
use FacebookAds\Object\Fields\AdAsyncRequestFields;

$request_set = new AdAsyncRequestSet(<REQUEST_SET_ID>);
$requests = $request_set->getRequests(array(
  AdAsyncRequestFields::ID,
  AdAsyncRequestFields::STATUS,
));
from facebookads.adobjects.adasyncrequest import AdAsyncRequest
from facebookads.adobjects.adasyncrequestset import AdAsyncRequestSet

request_set = AdAsyncRequestSet(<REQUEST_SET_ID>)
request_set.get_requests(fields=[
    AdAsyncRequest.Field.id,
    AdAsyncRequest.Field.status,
])
curl -G \
  -d 'fields=id,status' \
  -d 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.11/<REQUEST_SET_ID>/requests

This returns status and details of each request inside the async request set. For async ad creation, make one request to create one ad. The status param is used to filter requests by its own status and can be any combination of following values:

  • initial – Not processed yet.
  • in_progress – Request is processing
  • success – Request finished and succeeds.
  • error – Request finished and failed
  • canceled – Request canceled by user

The response is a JSON array with default fields. To include any non-default field, specify it in fields, such as fields=id,scope_object_id,status,result,input,async_request_set.

Name Type Description Shown by default

id

int

Individual async request ID

yes

scope_object_id

int

Parent id of object this request creates. If you create an ad, this is ad set ID for the new ad.

yes

status

string

Status of this async request. Options:


Initial – Not processed yet


In_progress – Request is processing


Success – Request finished and succeeds


Error – Request finished and failed


Canceled – Request is canceled by user

yes

result

array

If request is finished, shows result of the request.
On success, the result is the same as a non-async request. For example, if you create an ad, the result for each request is the ID of the new ad. For errors, it will be array of:


error_code – Error code returned


error_message – Error message

no

input

object

Original input for this async request. If you create an ad, the input is adgroup_spec.

no

async_request_set

object

Async request set that contains this individual request

no

Get Request Details

To get details of a specific async request, make this call:

use FacebookAds\Object\AdAsyncRequest;
use FacebookAds\Object\Fields\AdAsyncRequestFields;

$request = new AdAsyncRequest(<REQUEST_ID>);
$request->read(
  array(
    AdAsyncRequestFields::ID,
    AdAsyncRequestFields::STATUS,
  ));
from facebookads.adobjects.adasyncrequest import AdAsyncRequest

request = AdAsyncRequest(<REQUEST_ID>)
request.remote_read(fields=[
    AdAsyncRequest.Field.id,
    AdAsyncRequest.Field.status,
])
curl -G \
  -d 'fields=id,status' \
  -d 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.11/<REQUEST_ID>

This returns a JSON object with fields listed above.

List Request Sets for an Account

You can create multiple async ad request sets. To query all async ad request sets for an ad account:

use FacebookAds\Object\AdAccount;
use FacebookAds\Object\Fields\AdAsyncRequestSetFields;

$account = new AdAccount('act_<AD_ACCOUNT_ID>');
$request_sets = $account->getAsyncAdRequestSets();
from facebookads.adobjects.adaccount import AdAccount

account = AdAccount('act_<AD_ACCOUNT_ID>')
request_sets = account.get_async_ad_request_sets()
curl -G \
  -d 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.11/act_<AD_ACCOUNT_ID>/asyncadrequestsets

This returns a JSON array of async request set objects. Each object is the same as specified in async request set section. You can filter results with is_completed. If is_completed=true, you see only completed async request set.

List Requests for an Ad Set

You can make an async call to create ads in different ad sets. To get the status for each ad set, get all ad creation requests for one ad set:

use FacebookAds\Object\AdSet;
use FacebookAds\Object\Fields\AdAsyncRequestFields;

$adset = new AdSet(<AD_SET_ID>);
$async_requests = $adset->getAsyncAdRequests(array(
  AdAsyncRequestFields::ID,
  AdAsyncRequestFields::STATUS,
));
from facebookads.adobjects.adset import AdSet
from facebookads.adobjects.adasyncrequest import AdAsyncRequest

ad_set = AdSet(<AD_SET_ID>)
ad_iter = ad_set.get_async_ad_requests(fields=[
    AdAsyncRequest.Field.id,
    AdAsyncRequest.Field.status,
])
curl -G \
  -d 'fields=id,status' \
  -d 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.11/<AD_SET_ID>/asyncadrequests

This returns a JSON array of async request objects. The status, fields filter and async request fields are the same as https://graph.facebook.com/&lt;API_VERSION>/&lt;REQUEST_SET_ID>/requests API

Update Request Sets

You can change name, notification_uri and notification_modefor an async request set.

use FacebookAds\Object\AdAsyncRequestSet;
use FacebookAds\Object\Fields\AdAsyncRequestSetFields;
use FacebookAds\Object\Values\AdAsyncRequestSetNotificationModeValues;

$request_set = new AdAsyncRequestSet(<REQUEST_SET_ID>);

$request_set->update(array(
  AdAsyncRequestSetFields::NAME => 'New Name',
  AdAsyncRequestSetFields::NOTIFICATION_MODE =>
    AdAsyncRequestSetNotificationModeValues::OFF,
));
from facebookads.adobjects.adasyncrequestset import AdAsyncRequestSet

request_set = AdAsyncRequestSet(<REQUEST_SET_ID>)
request_set[AdAsyncRequestSet.Field.name] = 'New Name'
request_set[AdAsyncRequestSet.Field.notification_mode] = \
    AdAsyncRequestSet.NotificationMode.off
request_set.remote_update()
curl \
  -F 'name=New Name' \
  -F 'notification_mode=OFF' \
  -F 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.11/<REQUEST_SET_ID>

This return true on successful update. You can only change notification_uri and notification_mode before the notification is sent.

Cancelling

You can cancel an async request; the request can only be cancelled if it is not processed yet.

use FacebookAds\Object\AdAsyncRequest;

$request = new AdAsyncRequest(<REQUEST_ID>);
$request->deleteSelf();
from facebookads.adobjects.adasyncrequest import AdAsyncRequest

request = AdAsyncRequest(<REQUEST_ID>)
request.remote_delete()
curl -X DELETE \
  -d 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.11/<REQUEST_ID>

Returns true on successful cancellation. You can also cancel unprocessed requests in the async request set:

use FacebookAds\Object\AdAsyncRequestSet;

$request_set = new AdAsyncRequestSet(<REQUEST_SET_ID>);
$request_set->deleteSelf();
from facebookads.adobjects.adasyncrequestset import AdAsyncRequestSet

request_set = AdAsyncRequestSet(<REQUEST_SET_ID>)
request_set.remote_delete()
curl -X DELETE \
  -d 'access_token=<ACCESS_TOKEN>' \
  https://graph.facebook.com/v2.11/<REQUEST_SET_ID>

Returns true on successful cancellation.

Async Examples

Getting status of a specific async request:

//pretty=true for command line readable output
curl -G \
-d "id=6012384857989" \
-d "pretty=true" \
-d "access_token=_____" \
"https://graph.facebook.com/<API_VERSION>/"

Return values:

{
   "id": "6012384857989",
   "owner_id": 12345,
   "name": "testasyncset",
   "is_completed": true
}

Get results of requests:

curl -G \
-d "id=6012384857989" \
-d "pretty=true" \
-d "fields=result" \
-d "access_token=_____" \
"https://graph.facebook.com/<API_VERSION>/requests"

Returns:

{
   "data": [
      {
         "result": {
            "id": "6012384860989"
         },
         "id": "6012384858389"
      },
      {
         "result": {
            "id": "6012384858789"
         },
         "id": "6012384858189"
      }
   ],
   "paging": {
      "cursors": {
         "after": "___",
         "before": "___"
      }
   }
}

Get list of request sets for an ad account:

curl -G \
-d "is_completed=1" \
-d "pretty=true" \
-d "access_token=___" \
"https://graph.facebook.com/<API_VERSION>/act_71597454/asyncadrequestsets"

Returns:

{
   "data": [
      {
         "id": "6012384253789",
         "owner_id": 71597454,
         "name": "testasyncset",
         "is_completed": true
      },
   ],
   "paging": {
      "cursors": {
         "after": "___",
         "before": "___"
      }
   }
}

Getting a list of requests for a campaign:

curl -G \
-d "status=SUCCESS,ERROR" \
-d "pretty=true" \
-d "access_token=___" \
"https://graph.facebook.com/<API_VERSION>/6008248529789/asyncadrequests"

Return values:

{
   "data": [
      {
         "id": "6012384951789",
         "scope_object_id": 6008248529789,
         "status": "SUCCESS"
      },
   ],
   "paging": {
      "cursors": {
         "after": "___",
         "before": "___"
      }
   }
}

Batch Requests

With batched requests, combine a number of Graph API calls into the one HTTP request. Marketing API split this request into its constituent requests. This makes batched requests the most efficient way of interacting with the Marketing API. For even greater efficiency you can make parallel batch requests using separate processing threads.

Note: Each batched request can contain a maximum of 50 requests. For ad creation you should only have 10 or less ads per batch.

Batch requests for ads, adcreatives and ad sets are very similar so we don't discuss them separately here. For more information, see Graph API batch requests and ETags.

Creating Ads

You can provide adcreative and other ad objects in a batched request. For example, you can create three ads using one adcreative and three different targeting specs. Define your Ad Creative first then reference it when you create each ad:

curl -F 'access_token=______' 
  -F 'test1=@./test1.jpg'  
  -F 'batch=[
             {
              "method": "POST",
              "name": "create_creative",
              "relative_url": "<API_VERSION>/act_187687683/adcreatives",
              "attached_files": "test1",
              "body": "title=Test title&amp;body=Test body&amp;link_url=http://www.test12345.com&amp;image_file=test1.jpg"
             },
             {
              "method": "POST",
              "relative_url": "<API_VERSION>/act_187687683/ads",
              "body": "adset_id=6004163746239&amp;redownload=1&amp;optimization_goal=REACH&amp;billing_event=IMPRESSIONS&amp;bid_amount=150&amp;creative={\"creative_id\":\"{result=create_creative:$.id}\"}&amp;targeting={\"countries\":[\"US\"]}&amp;name=test1"
             },
             {
              "method": "POST",
              "relative_url": "<API_VERSION>/act_187687683/ads",
              "body": "adset_id=6004163746239&amp;redownload=1&amp;optimization_goal=REACH&amp;billing_event=IMPRESSIONS&amp;bid_amount=150&amp;creative={\"creative_id\":\"{result=create_creative:$.id}\"}&amp;targeting={\"countries\":[\"GB\"]}&amp;name=test2"
             },
             {
              "method": "POST",
              "relative_url": "<API_VERSION>/act_187687683/ads",
              "body": "adset_id=6004163746239&amp;redownload=1&amp;optimization_goal=REACH&amp;billing_event=IMPRESSIONS&amp;bid_amount=150&amp;creative={\"creative_id\":\"{result=create_creative:$.id}\"}&amp;targeting={\"countries\":[\"IE\"]}&amp;name=test3"
             }
            ]' https://graph.facebook.com/

The response includes individual response codes for each request and the standard Graph API response. For details, see Making Multiple API Requests.

The batched request process uses the JSONPath expression format to reference the previous requests.

The next example creates three ads using two different images:

curl -F 'access_token=____' 
  -F 'test1=@./test1.jpg' 
  -F 'test2=@./test2.jpg' 
  -F 'batch=[
             {
              "method": "POST",
              "relative_url": "<API_VERSION>/act_187687683/ads",
              "attached_files": "test1",
              "body": "adset_id=6004163746239&amp;optimization_goal=REACH&amp;billing_event=IMPRESSIONS&amp;bid_amount=150&amp;creative={\"title\":\"Test title 1\",\"body\":\"Test body 1\",\"object_url\":\"https://apps.facebook.com/testapp/\", \"image_file\":\"test1.jpg\"}&amp;targeting={\"countries\":[\"US\"]}&amp;name=test1"
             },
             {
              "method": "POST",
              "relative_url": "<API_VERSION>/act_187687683/ads",
              "attached_files": "test2",
              "body": "adset_id=6004163746239&amp;optimization_goal=REACH&amp;billing_event=IMPRESSIONS&amp;bid_amount=150&amp;creative={\"title\":\"Test title 2\",\"body\":\"Test body 2\",\"object_url\":\"https://apps.facebook.com/testapp/\", \"image_file\":\"test2.jpg\"}&amp;targeting={\"countries\":[\"US\"]}&amp;name=test2"
             },
             {
              "method": "POST",
              "relative_url": "<API_VERSION>/act_187687683/ads",
              "attached_files": "test1",
              "body": "adset_id=6004163746239&amp;optimization_goal=REACH&amp;billing_event=IMPRESSIONS&amp;bid_amount=150&amp;creative={\"title\":\"Test title 3\",\"body\":\"Test body 3\",\"object_url\":\"https://apps.facebook.com/testapp/\", \"image_file\":\"test1.jpg\"}&amp;targeting={\"countries\":[\"US\"]}&amp;name=test3"
             }
           ]' https://graph.facebook.com

Updating Ads

You can update ads with batch requests. To updates bids for three ads:

curl -F 'access_token=____' 
  -F 'batch=[
             {
              "method": "POST",
              "relative_url": "<API_VERSION>/6004251715639",
              "body": "redownload=1&amp;bid_amount=100"
             },
             {
              "method": "POST",
              "relative_url": <API_VERSION>/v6004251716039",
              "body": "redownload=1&amp;bid_amount=100"
             },
             {
              "method": "POST",
              "relative_url": "<API_VERSION>/6004251715839",
              "body": "redownload=1&amp;bid_amount=100"
             }
            ]' https://graph.facebook.com

If you include redownload=1 in the relative URL, you get full ad details including the ad ID. This help identify which ads you updated.

To update ad creative, specify the entire creative, or provide a new creative ID. This is because Ad Creatives cannot be edited after they have been created except for name and run status.

Read Ads

If you have a large number of ads, split the request over multiple requests within a batched request:

curl -F 'access_token=____' 
  -F 'batch=[
             {
              "method": "GET",
              "relative_url": "<API_VERSION>/?ids=6003356308839,6004164369439&amp;fields=<comma separated list of fields>"
             },
             {
              "method": "GET",
              "relative_url": "<API_VERSION>/6003356307839/ads&amp;fields=<comma separated list of fields>"
             },
             {
              "method": "GET",
              "relative_url": "<API_VERSION>/act_187687683/ads?adset_ids=[6003356307839, 6004164259439]&amp;fields=<comma separated list of fields>"
             }
            ]' https://graph.facebook.com

6003356308839 and 6004164369439 are ad ids and 6003356307839 and 6004164259439 are ad set ids.


Ad Insights

If you have a large number of Ad Insights split the request over multiple requests within a batched request:

curl -F 'access_token=____' 
  -F 'batch=[
             {
              "method": "GET",
              "relative_url": "<API_VERSION>/act_19643108/insights?filtering=[{field:'ad.id',operator:'IN',value:[6003356308839,6004164369439]}]"
             },
             {
              "method": "GET",
              "relative_url": "<API_VERSION>/6003356308839/insights"
             },
             {
              "method": "GET",
              "relative_url": "<API_VERSION>/act_187687683/insights?filtering=[{field:'adset.id',operator:'IN',value:[6003356307839, 6004164259439]}]"
             }
            ]' https://graph.facebook.com

In this example 6003356308839 and 6004164369439 are ad ids and 6003356307839 and 6004164259439 are ad set ids.

For Ad accounts with a large number of ads using act_&lt;account_ID>/adgroupstats is not recommended as it may cause the request to timeout.

Batch requests for Reach Estimate

You can request up to 50 reach estimates in a single batched request. For example, to get the reach estimate for three different ads at the one time:

curl -F 'access_token=____' 
  -F 'batch=[
             {
              "method": "GET",
              "relative_url": "<API_VERSION>/6003356308839/reachestimate"
             },
             {
              "method": "GET",
              "relative_url": "<API_VERSION>/6004164369439/reachestimate"
             },
             {
              "method": "GET",
              "relative_url": "<API_VERSION>/6004017499039/reachestimate"
             }
            ]' https://graph.facebook.com

The following example shows the reach estimate being requested for 3 different targeting specs:

curl -F 'access_token=____' 
  -F 'batch=[
             {
              "method": "GET",
              "relative_url": "<API_VERSION>/act_600335/reachestimate?currency=USD&amp;targeting_spec={'countries':['US']}"
             },
             {
              "method": "GET",
              "relative_url": "<API_VERSION>/act_600335/reachestimate?currency=USD&amp;targeting_spec={'countries':['FR']}"
             },
             {
              "method": "GET",
              "relative_url": "<API_VERSION>/act_600335/reachestimate?currency=USD&amp;targeting_spec={'countries':['US'],'zips':['94402']}"
             }
            ]' https://graph.facebook.com

Batch API

Batch API enables you batch requests and send them asynchronously. Group several Graph API calls into one HTTP request, and execute them asynchronously without having to block. You can also specify dependencies between related operations. Facebook processes each independent operation in parallel processes and your dependent operations sequentially. Each API call can have a maximum of 1000 requests.

Making a Batch API call

To make a Batch API call:

curl \
-F "access_token=___" \
-F "name=asyncbatchreqs" \
-F "adbatch=<an array of requests>"\
"https://graph.facebook.com/<API_VERSION>/act_<AD_ACCOUNT_ID>/async_batch_requests"  

Provide an array of HTTP POST requests as JSON arrays. Each request has:

  • name
  • relative_url - portion of URL after graph.facebook.com
  • body

The API returns an id you use to query the progress of requests.

For example, create a campaign with an ad set with JSONPath Format to reference the previous requests:

curl \
-F "access_token=___" \
-F "name=batchapiexample" \
-F "adbatch=[
  {
    'name': 'create-campaign',
    'relative_url': 'act_123456/campaigns',
    'body': 'name%3DTest+Campaign%26objective%3DLINK_CLICKS%26status%3DPAUSED%26buying_type%3DAUCTION',
  },
  {
    'name': 'create-adset',
    'relative_url': 'act_123456/adsets',
    'body': 'targeting%3D%7B%22geo_locations%22%3A%7B%22countries%22%3A%5B%22US%22%5D%7D%7D%26daily_budget%3D5000%26campaign_id%3D%7Bresult%3Dcreate-campaign%3A%24.id%7D%26bid_amount%3D2%26name%3DFirst%2BAd%2BSet%20Test%26billing_event%3DLINK_CLICKS',
  },
]" \
https://graph.facebook.com/<API_VERSION>/act_123456/async_batch_requests

To get a request set status:

curl –G \
-d "access_token=___" \
-d "fields=<comma separated list of fields>" \
"https://graph.facebook.com/<API_VERSION>/<REQUEST_SET_ID>"  

This returns overall status for async request sets as JSON objects. Not all fields are returned by default. To include them, specify the fields, such as fields=id,owner_id,name,total_count,success_count,error_count,is_completed

Name Type Description Shown by default

id

int

id of current async request set

yes

owner_id

int

Object that owns this async request set. If you create ads, owner_id is the ad account id.

yes

name

string

Name of this async request set

yes

is_completed

bool

All async requests in set complete

yes

total_count

int

Total requests count for this request set

no

initial_count

int

Number of requests not served yet

no

in_progress_count

int

Number of requests in progress

no

success_count

int

Number of requests finished and successful

no

error_count

int

Number of requests finished and failed

no

canceled_count

int

Number of requests canceled by user

no

notification_uri

string

Notification URI for this async request set.

no

notification_mode

string

Ways to receive notification. Valid values:


OFF – No notifications


ON_COMPLETE – Send notification when the whole set done.

no

notification_result

string

Result of sending notification.

no

notification_status

string

Notification status: not_sent, sending, or sent

no

After you get overall status, you can get details for each request:

curl –G \   
-d "access_token=___" \
-d "fields=<comma separated list of fields>" \
"https://graph.facebook.com/<API_VERSION>/<REQUEST_SET_ID>/requests" 

This returns details as a JSON array. To include non-default fields, specify it in fields, such as fields=id,scope_object_id,status,result,input,async_request_set.

Name Type Description Shown by default

id

int

ID of individual async request

yes

scope_object_id

int

Parent ID of the object this request creates. If you create ads, this is ad set ID for the new ad.

yes

status

string

Status of this async request:


Initial – Not processed yet


In_progress – Request is processing


Success – Request finished and successful


Error – Request finished and failed


Canceled – Request canceled by user

yes

result

array

If request finishes, show result. For success, the result is same as non-async API. For example, if you create an ad creation, result is new ad ID. For errors:


error_code – Error code returned


error_message – Error message

no

input

object

Original input for this request. If you create an ad, the input is adgroup_spec.

no

async_request_set

object

Async request set containing this request

no

List Batch API Requests for Ad Account

You can create multiple Batch API request sets. To query all request sets under an ad account:

curl –G \ 
-d "access_token=___" \
"https://graph.facebook.com/<API_VERSION>/act_<AD_ACCOUNT_ID>/async_requests"

ETags

Marketing API supports Etags. This helps you tell if the data you query has changed since you last checked. How this works:

  1. When you make a call, the response header includes an ETag with a value that is the hash of the data returned in the API call. Save this ETag value for use in the next step.
  2. Next time you make the same API call, include the If-None-Match request header with the ETag value you saved.
  3. If the data has not changed, the response status code is 304 – Not Modified and no data is returned.
  4. If the data has changed since the last query, the data is returned as usual with a new ETag. Save the new ETag value and use it for subsequent calls.

While ETags help reduce data traffic, If-None-Match GET still counts against rate limits for your app.

The ETag is calculated using the entire response from the API call including its formatting. The formatting of the response may be impacted by the user agent string. Therefore, you should keep your user agent consistent between calls made from the same client.

Etags Examples

To check if the user's adaccounts have changed.

Step 1; Determine the ETag for the current data

curl -i "https://graph.beta.facebook.com/me/adaccounts?access_token=___"

The response will be as follows:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Cache-Control: private, no-cache, no-store, must-revalidate
Content-Type: text/javascript; charset=UTF-8
ETag: "7776cdb01f44354af8bfa4db0c56eebcb1378975"
Expires: Sat, 01 Jan 2000 00:00:00 GMT
Pragma: no-cache
X-FB-Rev: 495685
X-FB-Server: 10.30.149.204
X-FB-Debug: CWbHcogdwUE8saMv6ML+8FacXFrE8ufhjjwxU2dQWaA=
X-Cnection: close
Date: Mon, 16 Jan 2012 12:07:44 GMT
Content-Length: 3273

{"data":[{"id":"act.......

In this example the ETag is "7776cdb01f44354af8bfa4db0c56eebcb1378975", note that the ETag includes the quotes (").

Step 2; Determine if there have been any changes to the data

curl -i -H "If-None-Match: \"7776cdb01f44354af8bfa4db0c56eebcb1378975\"" "https://graph.beta.facebook.com/me/adaccounts?access_token=___"

If nothing has changed the response will be as follows:

HTTP/1.1 304 Not Modified
Access-Control-Allow-Origin: *
Cache-Control: private, no-cache, no-store, must-revalidate
Content-Type: text/javascript; charset=UTF-8
Expires: Sat, 01 Jan 2000 00:00:00 GMT
Pragma: no-cache
X-FB-Rev: 495685
X-FB-Server: 10.30.177.190
X-FB-Debug: ImBhat3k07Nez5FvuS2lPWU0U2xxmxD4B3k9ua4Sk7Q=
X-Cnection: close
Date: Mon, 16 Jan 2012 12:09:17 GMT
Content-Length: 0

Note the 304 Not Modified response. If the data had changed a normal API response would be returned.

A batch example to check if the user's ads have changed.

Step 1; Determine the ETag for the current data

curl -i "curl -F 'access_token=___' -F 'batch=[ 
  {"method":"GET", "relative_url": "?ids=6003356308839,6004164369439" }, 
  {"method":"GET", "relative_url": "act_12345678/ads?campaign_ids=[6003356307839, 6004164259439]"}]'
 https://graph.facebook.com"

The response will contain ETag values as follows:

...{"name":"ETag","value":"\"21d371640127490b2ed0387e8af3f0f8c9eff012\""}...      
...{"name":"ETag","value":"\"410e53bb257f116e8716e4ebcc76df1c567b87f4\""}...

In this example the ETags are "21d371640127490b2ed0387e8af3f0f8c9eff012" and "410e53bb257f116e8716e4ebcc76df1c567b87f4" note that the ETag includes the quotes (").

Step 2; Determine if there have been any changes to the data

curl -F 'access_token=___' -F 'batch=[
  {"method":"GET", "headers":["If-None-Match: \"21d371640127490b2ed0387e8af3f0f8c9eff012\""], "relative_url": "?ids=6003356308839,6004164369439" },
  {"method":"GET",  "headers":["If-None-Match: \"410e53bb257f116e8716e4ebcc76df1c567b87f4\""], "relative_url": "act_12345678/ads?campaign_ids=[6003356307839, 6004164259439]"}]' 
https://graph.facebook.com

If nothing has changed the response is:

[{
    "code": 304,
    .
    .
    .
    "body": null
},
{
    "code": 304,
    .
    .
    .
    "body": null
}]

Note the 304 Not Modified response. If the data changed, we return a normal API response