pythonjsonfacebookfacebook-graph-api

Weirdest issue with FB API response from Python SDK


Here's one of the weirdest issue I have ever experienced with an API. Let's see, so I am using the Facebook Business API, and it works fine for most requests I do, however there are some accounts that behave very strange.

Let's see, if I call this:

accounts_general_fields = ['account_id', 'business_name', 'account_status', 'age', 'amount_spent','balance','currency']

print(me.get_ad_accounts(fields=accounts_general_fields))

this works fine, there is not issue, however when I want to iterative over it, for example

accounts= list(me.get_ad_accounts(fields=accounts_general_fields))

accounts= me.get_ad_accounts(fields=accounts_general_fields)
accounts_fixed = [account.api_get(fields=accounts_general_fields) for account in accounts]
accounts= me.get_ad_accounts(fields=accounts_general_fields)
accounts_fixed = [account.export_all_data() for account in accounts]

or

accounts= me.get_ad_accounts(fields=accounts_general_fields)
accounts_fixed = [account for account in accounts]

it gets this:

facebook_business.exceptions.FacebookRequestError: 
  Message: Call was not successful
  Method:  GET
  Path:    https://graph.facebook.com/v20.0/me/adaccounts
  Params:  {'fields': 'account_id,business_name,account_status,age,amount_spent,balance,currency', 'summary': 'true', 'after': 'MjM4NDM4NDA2MTg4NjAxMjkZD'}
  Status:  400
  Response:
    {
      "error": {
        "message": "(#80004) There have been too many calls to this ad-account. Wait a bit and try again. For more info, please refer to https://developers.facebook.com/docs/graph-api/overview/rate-limiting#ads-management.",
        "type": "OAuthException",
        "code": 80004,
        "error_subcode": 2446079,
        "fbtrace_id": "ArA51rxNPTHAl7CrHVCaEWG"
      }
    }

This behavior happens with other endpoints, for example:

AdAccount(ad_account_id).get_campaigns(fields=fields)

and

AdAccount(ad_account_id).get_campaigns(fields=fields)

but just for specific ad accounts, like 3 or 4 accounts of 300 accounts. I don't know what could be happening. Here is my implementation for those endpoints:


def fetch_adsets_for_account(ad_account_id, fields):
    try:

        return list(AdAccount(ad_account_id).get_ad_sets(fields=fields))
    except Exception as e:
        print(f"Failed to fetch ad sets for ad account {ad_account_id}: {e}")
        return []

def fetch_adsets_data(ad_account_ids, fields):

    all_data = []

    # Use ThreadPoolExecutor to fetch data in parallel
    with concurrent.futures.ThreadPoolExecutor(max_workers=30) as executor:
        # Create a list of futures
        futures = {executor.submit(fetch_adsets_for_account, ad_account_id, fields): ad_account_id for ad_account_id in ad_account_ids}

        # As each future completes, append the result to all_data
        for future in concurrent.futures.as_completed(futures):
            try:
                data = future.result()
                all_data.extend(data)
            except Exception as e:
                ad_account_id = futures[future]
                print(f"An error occurred for ad account {ad_account_id}: {e}")

    # Convert the collected data to a DataFrame
    df = pd.DataFrame(all_data)
    return df

#  Example usage:
ad_account_ids = df_accounts["id"].tolist()[:]
fields = ['name', 'status', 'start_time', 'lifetime_budget']

start = time.time()
df_individual_adsets = fetch_adsets_data(ad_account_ids, fields)
df_individual_adsets["date"] = today_data

end = time.time()

print(end - start)

Here's one example of the problem for this:

Failed to fetch ad sets for ad account act_400136354038554: 
  Message: Call was not successful
  Method:  GET
  Path:    https://graph.facebook.com/v20.0/act_400136354038554/adsets
  Params:  {'fields': 'name,status,start_time,lifetime_budget', 'summary': 'true', 'after': 'QVFIUmM2a3VXdG5XRG43OFd3ZAVdLNlV5d1BaR3NlWFlyTk9zQW5yaElIYWZAieVF0b3pFMUphV0tIZAmR4VEE2S3J0LTIZD'}
  Status:  400
  Response:
    {
      "error": {
        "message": "User request limit reached",
        "type": "OAuthException",
        "is_transient": false,
        "code": 17,
        "error_subcode": 2446079,
        "error_user_title": "Ad Account Has Too Many API Calls",
        "error_user_msg": "There have been too many calls from this ad-account. Please wait a bit and try again.",
        "fbtrace_id": "A-LW6ciS_vyN_vkhK5CD0tW"
      }
    }

Solution

  • Facebook Business SDK for Python sucks, I solved this issue with this:

    def fetch_adsets_for_account(ad_account_id, fields):
      try:
        data = AdAccount(ad_account_id).get_ad_sets(fields=fields, params={"limit": 2000})
        data_final = [data.export_all_data() for data in data]
        return data_final
      except Exception as e:
        print(f"Failed to fetch ad sets for ad account {ad_account_id}: {e}")
        return []
    

    Essentially you only need to define a high limit and it will work as expected!