Posts under category facebook-graph-api

I'm trying to make a bot that replies to facebook comments on my page's livestream. Unfortunately, after a few replies, Facebook send back an error message with code 368 and I can only send more replies after a few seconds. The full message is:

We limit how often you can post, comment or do other things in a given amount of time in order to help protect the community from spam. You can try again later 

The API I'm using is /${page_id}/comments
There seem to be a lot of people got into my issue as well: https://developers.facebook.com/support/bugs/938590201317189

Page access token expires periodically and if it expires, I need to generate a new one manually.

Is it possible if the page access token can be refresh via code?

Here's my code in react typescript:

const PAGE_ACCESS_TOKEN = "EAAcAHP"; const PAGE_ID = "123456"; export const fetchPageFeed = async () => {   try {     // Fetch page profile picture     const pageInfoResponse = await axios.get(       `https://graph.facebook.com/${PAGE_ID}`,       {         params: {           access_token: PAGE_ACCESS_TOKEN,           fields: "picture{url},name,link",          },       }     );     // Fetch page posts     const postsResponse = await axios.get(       `https://graph.facebook.com/${PAGE_ID}/posts`,       {         params: {           access_token: PAGE_ACCESS_TOKEN,           fields:             "id,message,created_time,picture,full_picture,attachments{media_type,media},reactions.summary(total_count),comments.summary(total_count),shares,video_tags,videos{source,description,thumbnails}",         },       }     );     return {       profilePictureUrl: pageInfoResponse.data.picture.data.url,       pageName: pageInfoResponse.data.name,       pageUrl: pageInfoResponse.data.link,        posts: postsResponse.data.data,     };   } catch (error) {     console.error("Error fetching page feed:", error);     return { profilePictureUrl: "", pageName: "", pageUrl: "", posts: [] };    } }; 

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"       }     } 

I have big app for managing/organizing photos. One of functionality is publishing (with rescaling, adding signature etc.) with descriptions (from program database). I added e.g. publishing to Skyscrapercity. Now I want to add publishing to: *) Instagram, to my own account *) Facebook: **) post to my own accoount, **) creating albums in my own account, **) post to group I belong (multi pic to one post, with metadata/description to each pic)

I think facebook login as "device login" would be best, because it doesn't require adding http server functionality to my app. But it seems that I should first get access code. When I try to do it, I got message that my app is not allowed to use login (but it has 'device login' enabled). I suspect that I have to convert my private account to business account, than allow my app to be verified by Facebook - but app has ~15 thousands lines of code, so it would take months :)

Can anyone give me some hints / guide me through adding FB posting functionality to desktop WPF app?

    var sUri = $"https://graph.facebook.com/v2.6/device/login?access_token={FB_APP_ID}|{FB_CLNT_TOKEN}&scope=public_profile"     var sPage = await Vblib.HttpPageAsync(sUri)     // got: (#3) Application does not have the capability to make this API call. 

Where HttpPageAsync is library function, in short (stripping down error handling etc.)

    var oResp = await moHttp.GetAsync(oUri)     var sPage = await oResp.Content.ReadAsStringAsync() 

New reel does appear in fan page's Reels feed but it's invisible to users (i used another account to display the same feed and new reel is not there).

My "Page" perms:

publish_video pages_show_list pages_read_engagement pages_manage_posts 

Using this Python code to publish Facebook reel:

import os import requests from os.path import isfile page_id= 'your business page id' api_version= 'v20.0' page_access_token= 'your_page_token' def initialize_upload():     url = f"https://graph.facebook.com/{api_version}/{page_id}/video_reels"     payload = {         'upload_phase': 'start',         'access_token': page_access_token     }     r = requests.post(url, data=payload)     json = r.json()     if r.status_code == 200:         video_id = r.json()['video_id']     else:         raise Exception(json)      return video_id def process_upload(video_id, file_size, file_data):       url = f'https://rupload.facebook.com/video-upload/{api_version}/{video_id}'     payload = {         'Authorization': 'OAuth ' + page_access_token,         'offset': '0',         'file_size': str(file_size),         'Content-Type': 'application/octet-stream'     }     r = requests.post(url, data=file_data, headers=payload)     json = r.json()     if r.status_code != 200:         raise Exception(json) def publish(video_id, description, publish_time=None):     url = f"https://graph.facebook.com/{api_version}/{page_id}/video_reels"     payload = {         'access_token': page_access_token,         'video_id': video_id,         'upload_phase': 'finish',         'description': description,     }     if publish_time:         payload['video_state'] = 'SCHEDULED'         payload['scheduled_publish_time'] = publish_time     else:         payload['video_state'] = 'PUBLISHED'     r = requests.post(url, data=payload)     json = r.json()     if r.status_code != 200:         raise Exception(json) if __name__ == '__main__':     video_id = initialize_upload()     print(video_id)          mp4_path= r"C:\test\Facebook.mp4"              if isfile(mp4_path):         file_size = os.path.getsize(mp4_path)         file_data= open(mp4_path, 'rb')         process_upload(video_id, file_size, file_data)         publish(video_id,  '#description')     else:         print('File not found') 

Metadata (those views are mine):

{'comments': {'data': [],               'summary': {'can_comment': True,                           'order': 'chronological',                           'total_count': 0}},  'created_time': '2024-08-13T16:22:02+0000',  'description': '#test',  'from': {'id': '***', 'name': 'Test'},  'id': '***',  'is_crossposting_eligible': True,  'likes': {'data': [],            'summary': {'can_like': True, 'has_liked': False, 'total_count': 0}},  'permalink_url': '/reel/***/',  'privacy': {'allow': '',              'deny': '',              'description': 'Public',              'friends': '',              'networks': '',              'value': 'EVERYONE'},  'status': {'copyright_check_status': {'matches_found': False,                                        'status': 'complete'},             'processing_phase': {'status': 'complete'},             'publishing_phase': {'publish_status': 'published',                                  'publish_time': '2024-08-13T17:33:12+0000',                                  'status': 'complete'},             'uploading_phase': {'bytes_transferred': 13671054,                                 'status': 'complete'},             'video_status': 'ready'},  'views': 45} 

Any idea why is it private?