The Offline Conversions API stopped working from Graph API version v17 onwards. Now, the Conversions API accepts both Online and Offline data.
I am trying to adapt to these changes but am facing some issues during development. Below is the code for a better understanding of the case:
Imports
from facebook_business.api import FacebookAdsApi
from facebook_business.adobjects.business import Business
from facebook_business.adobjects.adaccount import AdAccount
import json
import hashlib
from datetime import date
import boto3
from datetime import datetime
from pyspark.sql.functions import sha2, lower, trim, regexp_replace, translate
import re
import requests
import time
Establishing a session with AWS Secrets Manager to retrieve Facebook credentials.
session = boto3.session.Session()
client = session.client(
service_name='secretsmanager',
region_name='random-region'
)
response = client.get_secret_value(
SecretId='mysecret'
)
database_secrets = json.loads(response['SecretString'])
app_id = (database_secrets['app_id'])
app_secret= (database_secrets['app_secret'])
access_token = (database_secrets['access_token'])
FacebookAdsApi.init(app_id=app_id, app_secret=app_secret, access_token=access_token)
business_id = 'my_businnes_id'
business = Business(business_id)
ad_accounts = business.get_owned_ad_accounts(fields=['id','name'])
Query Delta Table
query = spark.sql("SELECT * FROM My_Query")
df = query
Hashing certain fields for privacy compliance
hashed_df = df.selectExpr(
"event_time",
"event_name",
"replace(value, ',', '.') as value",
"currency",
"data_processing_options",
"sha2(trim(lower(email)), 256) as em",
"sha2(ltrim(regexp_replace(phone, '[^0-9]', ''), '0'), 256) as ph",
"sha2(trim(lower(fn)), 256) as fn",
"sha2(trim(lower(ln)), 256) as ln",
"sha2(regexp_replace(trim(dt_nascimento), '[^a-zA-Z0-9]', ''), 256) as db",
"sha2(regexp_replace(translate(trim(lower(cidade)), 'áãâéêíóôõúÁÃÂÉÊÍÓÔÕÚ', 'aaaeeiooouAAAEEIOOOU'), ' ', ''), 256) as ct",
"sha2(regexp_replace(CAST(venda_ido AS STRING), '[^a-zA-Z0-9]', ''), 256) as order_id",
"sha2(regexp_replace(sku, '[^a-zA-Z0-9]', ''), 256) as item_code",
"sha2(regexp_replace(trim(lower(grupo_produto)), '[^a-zA-Z0-9]', ''), 256) as grupo_produto",
"sha2(regexp_replace(trim(lower(subcategoria)), '[^a-zA-Z0-9]', ''), 256) as subcategoria",
"sha2(regexp_replace(trim(lower(nm_segmento)), '[^a-zA-Z0-9]', ''), 256) as nm_segmento",
"store_code"
)
Defining a function to extract the store code from the account name
def extract_store_code(account_name):
match = re.search(r'^(\d+)\s', account_name)
return match.group(1) if match else None
Sending Data to Facebook
max_retries = 150
wait_seconds = 10
for ad_account in ad_accounts:
ad_account_id = ad_account['id']
ad_account_name = ad_account['name']
store_code = extract_store_code(ad_account_name)
relevant_events = [event for event in events_data if event['store_code'] == store_code]
if not relevant_events:
print(f"None {ad_account_id} (Store: {store_code})")
continue
account = AdAccount(ad_account_id)
for event in relevant_events:
attempt = 0
while attempt < max_retries:
try:
event_data = {
"event_name": event['event_name'],
"event_time": event['event_time'],
"action_source": "offline",
"event_source_url": "http://www.mysite.com.br",
"user_data": {
"em": event['em'],
"ph": event['ph'],
"fn": event['fn'],
"ln": event['ln'],
"db": event['db'],
"ct": event['ct']
},
"custom_data": {
"value": event['value'],
"currency": event['currency'],
"order_id": event['order_id'],
"item_code": event['item_code'],
"grupo_produto": event['grupo_produto'],
"subcategoria": event['subcategoria'],
"nm_segmento": event['nm_segmento']
}
}
params = {
'data': [event_data],
'access_token': access_token
}
response = account.create_event(params=params)
if response and 'success' in response and response.get('success'):
print(f"Event sended to {ad_account_id}.")
break
else:
print(f"Error {ad_account_id}: {response}")
attempt += 1
except Exception as e:
attempt += 1
if attempt < max_retries:
print(f"Waiting {wait_seconds} seconds...")
time.sleep(wait_seconds)
Errors:
Error: Exception on attempt 1 to send event to account act_000000myID: 'AdAccount' object has no attribute 'create_event''
I tried this method:
max_retries = 150
wait_seconds = 10
base_url = 'https://graph.facebook.com/v19.0'
for ad_account in ad_accounts:
ad_account_id = ad_account['id']
ad_account_name = ad_account['name']
# Filters relevant events for the current account based on 'store_code'
relevant_events = [event for event in events_data if str(event['store_code']) == extract_store_code(ad_account_name)]
if not relevant_events:
print(f"No relevant event for the account {ad_account_id} (Store: {extract_store_code(ad_account_name)})")
continue
url = f'{base_url}/{ad_account_id}/events'
for event in relevant_events:
attempt = 0
while attempt < max_retries:
try:
# Preparing the event payload according to the API structure
event_payload = {
'data': [event],
'access_token': access_token
}
response = requests.post(url, json=event_payload)
response_data = response.json()
if response.status_code == 200 and 'success' in response_data and response_data['success']:
print(f"Event successfully sent to the account {ad_account_id}.")
break
else:
print(f"Error sending event to the account {ad_account_id}: {response_data}")
attempt += 1
except Exception as e:
print(f"Exception on attempt {attempt + 1} to send event to the account {ad_account_id}: {e}")
attempt += 1
if attempt < max_retries:
print(f"Waiting {wait_seconds} seconds before trying again...")
time.sleep(wait_seconds)
Error:
Error sending event to the account act_000000myID: {'error': {'message': "Unsupported post request. Object with ID 'act_000000myID' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https://developers.facebook.com/docs/graph-api", 'type': 'GraphMethodException', 'code': 100, 'error_subcode': 33, 'fbtrace_id': 'AhbJaI_6XiSAvZu9w3c7hsC'}}
My Token have this permitions:
manage_fundraisers read_insights catalog_management ads_management ads_read business_management email pages_show_list instagram_basic instagram_manage_comments instagram_content_publish pages_read_engagement pages_manage_metadata pages_manage_posts