전환 API를 위한 Meta 비즈니스 SDK 기능

이 가이드는 전환 API 사용자를 위해 설계된 Meta 비즈니스 SDK 고급 기능을 둘러보는 데 도움이 됩니다. 비동기식 요청, 동시 일괄 처리HTTP 서비스 인터페이스는 PHP, NodeJS, Java, Python 및 Ruby SDK로 제공됩니다. 기본 전환 API 사용량의 경우 기본 전환 API 문서를 참조하세요.

Meta 비즈니스 SDK를 사용하면 비즈니스와 고객에게 도움이 되는 고유한 맞춤형 솔루션을 구축하기 위한 비즈니스 API 모음에 액세스할 수 있습니다. SDK 사용자에게 제공되는 API 중 하나가 전환 API입니다.

요구 사항

아래에 나와 있는 기능을 사용하기 전에 Meta 비즈니스 SDK를 설치해야 합니다. Meta 비즈니스 SDK 시작하기를 참조하거나 다음에 나와 있는 README 지침을 따르세요.

이러한 기능을 사용하는 데 필요한 최소 언어 버전은 다음과 같습니다.

  • PHP >= 7.2
  • Node.js >= 7.6.0
  • Java >= 8
  • Python >= 2.7
  • Ruby >= 2

비동기식 요청

요청이 완료될 때까지 기다리기 위해 프로그램 실행을 차단하고 싶지 않은 경우 이 기능을 사용하세요. 이 접근 방식에서는 요청을 보내고 요청 완료 후 서버로부터 다시 시그널을 받습니다. 응답을 기다리는 동안 프로그램을 계속 실행할 수 있습니다.

비동기식 요청을 사용하면 리소스를 더 효율적으로 사용할 수 있으므로 서버 응답 시간이 단축됩니다. 또한 프로그램에서 서버에서 발생하는 오류를 처리하는 방법을 더 잘 제어할 수 있고 이미 비동기적으로 실행되는 코드에 SDK를 쉽게 통합할 수 있습니다.

비동기식 요청을 구현하려면 다음 언어의 코드 샘플을 참조하세요.

use FacebookAds\Api;
use FacebookAds\Object\ServerSide\CustomData;
use FacebookAds\Object\ServerSide\Event;
use FacebookAds\Object\ServerSide\EventRequest;
use FacebookAds\Object\ServerSide\EventRequestAsync;
use FacebookAds\Object\ServerSide\UserData;

use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Promise;

$pixel_id = getenv('PIXEL_ID');
$access_token = getenv('ACCESS_TOKEN');

if (empty($pixel_id) || empty($access_token)) {
  throw new Exception('Missing required test config. Got pixel_id: "' . $pixel_id . '", access_token: "' . $access_token . '"');
}

Api::init(null, null, $access_token, false);

function create_events($num) {
  $user_data = (new UserData())
    ->setEmail('joe' . $num . '@eg.com')
    ->setClientIpAddress($_SERVER['REMOTE_ADDR'])
    ->setClientUserAgent($_SERVER['HTTP_USER_AGENT']);

  $custom_data = (new CustomData())
    ->setCurrency('usd')
    ->setValue(123.45);

  $event = (new Event())
    ->setEventName('Purchase')
    ->setEventTime(time())
    ->setEventSourceUrl('http://jaspers-market.com/product/123')
    ->setUserData($user_data)
    ->setCustomData($custom_data)
    ->setActionSource(ActionSource::WEBSITE);

  return array($event);
}

function create_async_request($pixel_id, $num) {
  $async_request = (new EventRequestAsync($pixel_id))
    ->setEvents(create_events($num));
  return $async_request->execute()
    ->then(
      null,
      function (RequestException $e) {
        print(
          "Error!!!\n" .
          $e->getMessage() . "\n" .
          $e->getRequest()->getMethod() . "\n"
        );
      }
    );
}


// Async request:
$promise = create_async_request($pixel_id, 2);

print("Request 1 state: " . $promise->getState() . "\n");
print("Async request - OK.\n");


// Async request with wait:
$promise = create_async_request($pixel_id, 3);

$response2 = $promise->wait();
print("Request 2: " . $response2->getBody() . "\n");
print("Async request with wait - OK.\n");


// Multiple async requests:
$promises = [
  "Request 3" => create_async_request($pixel_id, 4),
  "Request 4" => create_async_request($pixel_id, 5),
];

$response3 = Promise\unwrap($promises);
foreach ($response3 as $request_name => $response) {
  print($request_name . ": " . $response->getBody()."\n");
}
print("Async - Multiple async requests OK.\n");
import asyncio
import time
import pprint
import os
import sys
repo_dir = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)
sys.path.insert(1, repo_dir)

from facebook_business.adobjects.serverside.custom_data import CustomData
from facebook_business.adobjects.serverside.event import Event
from facebook_business.adobjects.serverside.event_request import EventRequest
from facebook_business.adobjects.serverside.event_request_async import EventRequestAsync
from facebook_business.adobjects.serverside.user_data import UserData
from facebook_business.api import FacebookAdsApi


def create_events(num):
    user_data = UserData(
        email="joe%s@eg.com" % num,
        client_ip_address=request.META.get('REMOTE_ADDR'),
        client_user_agent=request.headers['User-Agent']
    )
    custom_data = CustomData(currency="usd", value=123.45, item_number="itemnumber-123")
    event = Event(
        event_name="Purchase",
        event_time=int(time.time()),
        user_data=user_data,
        custom_data=custom_data,
        data_processing_options=[],
        event_source_url='http://jaspers-market.com/product/123',
        action_source=ActionSource.WEBSITE
    )
    return [event]

async def execute_async_request(pixel_id, num):
    event_request_async = EventRequestAsync(
        events=create_events(num),
        pixel_id=pixel_id
    )
    return await event_request_async.execute()

async def run_tasks(pixel_id):
    tasks = []
    for i in range(1,3):
        tasks.append(execute_async_request(pixel_id, i))

    completed = await asyncio.gather(*tasks)
    pp = pprint.PrettyPrinter(indent=4)
    pp.pprint(completed)

if __name__ == '__main__':
    pixel_id = os.getenv("PIXEL_ID")
    access_token = os.getenv("ACCESS_TOKEN")
    if not (pixel_id and access_token):
        raise Exception("Missing required test config. Got pixel_id: '{pixel_id}', access_token: '{access_token}'".format(
            pixel_id=pixel_id,
            access_token=access_token
        ))
    FacebookAdsApi.init(access_token=access_token, crash_log=False)

    asyncio.run(run_tasks(pixel_id))
    print("Create EventRequest Async - OK.")
const bizSdk = require('facebook-nodejs-business-sdk');
const process = require('process');
const ServerEvent = bizSdk.ServerEvent;
const EventRequest = bizSdk.EventRequest;
const UserData = bizSdk.UserData;
const CustomData = bizSdk.CustomData;
const Content = bizSdk.Content;

const access_token = process.env.ACCESS_TOKEN;
const pixel_id = process.env.PIXEL_ID;
void async function() {
  try {
    if (access_token === undefined || pixel_id === undefined) {
      throw new Error(`"Missing required test config. Got pixel_id: '${pixel_id}', access_token: '${access_token}'"`)
    }
    const api = bizSdk.FacebookAdsApi.init(access_token);

    let current_timestamp = Math.floor(new Date() / 1000);

    const userData1 = (new UserData())
      .setEmail('joe1@eg.com')
      .setClientIpAddress(request.connection.remoteAddress)
      .setClientUserAgent(request.headers['user-agent']);

    const customData1 = (new CustomData())
      .setCurrency('usd')
      .setCustomProperties({custom1: 'value2'})
      .setValue(123.45);

    const serverEvent1 = (new ServerEvent())
      .setEventName('Purchase')
      .setEventTime(current_timestamp)
      .setUserData(userData1)
      .setCustomData(customData1)
      .setEventSourceUrl('http://jaspers-market.com/product/123')
      .setActionSource('website');

    const eventRequest1 = (new EventRequest(access_token, pixel_id))
      .setEvents([serverEvent1]);

    const userData2 = (new UserData())
      .setEmail('joe2@eg.com')
      .setClientIpAddress(request.connection.remoteAddress)
      .setClientUserAgent(request.headers['user-agent']);

    const customData2 = (new CustomData())
      .setCurrency('usd')
      .setCustomProperties({custom1: 'value2'})
      .setValue(123.45);

    const serverEvent2 = (new ServerEvent())
      .setEventName('Purchase')
      .setEventTime(current_timestamp)
      .setUserData(userData2)
      .setCustomData(customData2)
      .setEventSourceUrl('http://jaspers-market.com/product/123')
      .setActionSource('website');

    const eventRequest2 = (new EventRequest(access_token, pixel_id))
      .setEvents([serverEvent2]);

    Promise.all([
      eventRequest1.execute(),
      eventRequest2.execute()
    ]).then(response => {
      console.log('Execute 2 Requests OK. Response: ', response);
    }, err => {
      console.log('Error: ', err);
    });
  } catch(error) {
    console.log(error);
    process.exit(1);
  }
}();
import com.facebook.ads.sdk.APIContext;
import com.facebook.ads.sdk.serverside.Event;
import com.facebook.ads.sdk.serverside.EventRequest;
import com.facebook.ads.sdk.serverside.EventResponse;
import com.facebook.ads.sdk.serverside.UserData;
import com.facebook.ads.sdk.serverside.CustomData;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class CONVERSIONS_API_EVENT_CREATE_ASYNC {
  public static final String ACCESS_TOKEN = System.getenv("ACCESS_TOKEN");
  public static final String PIXEL_ID = System.getenv("PIXEL_ID");

  private static EventRequest getEventRequest(APIContext context, int num) {
    UserData userData = new UserData()
      .email(String.format("joe%s@eg.com", num))
      .clientIpAddress(clientIpAddress)
      .clientUserAgent(clientUserAgent);

    HashMap<String,String> customProperties = new HashMap<>();
    customProperties.put("custom1", "value2");

    CustomData customData = new CustomData()
      .currency("usd")
      .customProperties(customProperties)
      .value(123.45F);

    Event pageViewEvent = new Event();
    pageViewEvent.eventName("Purchase")
      .eventTime(System.currentTimeMillis() / 1000L)
      .userData(userData)
      .customData(customData)
      .eventSourceUrl("http://jaspers-market.com/product/123")
      .actionSource(ActionSource.website);

    EventRequest eventRequest = new EventRequest(PIXEL_ID, context);
    eventRequest.addDataItem(pageViewEvent);

    return eventRequest;
  }

  private static void run() throws Exception {
    if (ACCESS_TOKEN == null || PIXEL_ID == null) {
      throw new Exception(String.format("Missing required test config. Got pixel_id: '%s', access_token: '%s'", PIXEL_ID, ACCESS_TOKEN));
    }
    APIContext context = new APIContext(ACCESS_TOKEN);
    context.setLogger(System.out);

    EventRequest asyncRequest = getEventRequest(context, 1);
    final ListenableFuture<EventResponse> requestFuture = asyncRequest.executeAsync();
    EventResponse asyncResponse = requestFuture.get();
    System.out.println(String.format("Async Request - OK: %s", asyncResponse));

    List<ListenableFuture<EventResponse>> eventFutures = new ArrayList<>();
    eventFutures.add(getEventRequest(context, 2).executeAsync());
    eventFutures.add(getEventRequest(context, 3).executeAsync());
    eventFutures.add(getEventRequest(context, 4).executeAsync());
    List<EventResponse>
require 'concurrent'
require 'facebook_ads'
require 'pp'

ACCESS_TOKEN = ENV['ACCESS_TOKEN']
PIXEL_ID = ENV['PIXEL_ID']
unless ACCESS_TOKEN && PIXEL_ID
    raise Exception.new("Missing required test config. Got pixel_id: '#{PIXEL_ID}', access_token: '#{ACCESS_TOKEN}'")
end

FacebookAds.configure do |config|
    config.access_token = ACCESS_TOKEN
end

def get_events(num)
    user_data = FacebookAds::ServerSide::UserData.new(
        email: 'joe#{num}@eg.com',
        client_ip_address: request.remote_ip,
        client_user_agent: request.user_agent
    )

    custom_data = FacebookAds::ServerSide::CustomData.new(
        currency: 'usd',
        value: 123.45
    )

    event = FacebookAds::ServerSide::Event.new(
        event_name: 'Purchase',
        event_time: Time.now.to_i,
        user_data: user_data,
        custom_data: custom_data,
        event_source_url: 'http://jaspers-market.com/product/123',
        action_source: 'website'
    )

    [event]
end

def get_event_request_async(num)
    FacebookAds::ServerSide::EventRequestAsync.new(
        pixel_id: PIXEL_ID,
        events: get_events(num)
    )
end

def main
    request = get_event_request_async(1)
    response = request.execute.value!
    print "Response: #{response}\n"
    print "EventRequest async single - OK.\n"

    promises = (2..3).map {|num| get_event_request_async(num).execute }
    responses = Concurrent::Promise.zip(*promises)
        .execute
        .value!
    print "Responses:\n"
    pp responses
    print "EventRequest async multi - OK.\n"
end

main

동시 일괄 처리

동시 일괄 처리는 비동기식 요청을 활용하여 리소스를 보다 효율적으로 활용함으로써 처리량을 늘립니다. 일괄 처리된 요청을 만들어서 이벤트 요청 작업자, cron 작업 등의 사용 사례를 지원할 수 있습니다.

다음 BatchProcessor 메서드 중에서 선택할 수 있습니다.

메서드권장 사용 사례

processEvents

동일한 최상위 수준 EventRequest 필드(예: namespace_id, upload_tag)가 있는 이벤트를 처리하는 데 사용합니다.

processEventsGenerator

processEvents에 대한 기본 생성자입니다.


동일한 최상위 수준 EventRequest 필드(예: namespace_id, upload_tag)가 있는 이벤트를 처리하는 데도 사용할 수 있습니다.

processEventRequests

요청당 다른 EventRequest 필드를 지정하고자 하는 경우 EventRequests를 동시에 처리하는 데 사용합니다.

processEventRequestsGenerator

processEventRequests에 대한 기본 생성자입니다.


요청당 다른 EventRequest 필드를 지정하고자 하는 경우 EventRequests를 동시에 처리하는 데 사용할 수도 있습니다.

동시 일괄 처리를 사용할 때 이벤트는 최대한 실시간에 가깝게 전송해야 합니다. 자세한 내용은 공유 빈도를 참조하세요.

PHP, Python 또는 Ruby SDK를 사용하는 경우 위의 메서드에는 EventRequest가 아니라 EventRequestAsync가 필요합니다.

동시 일괄 처리를 구현하려면 다음 언어의 코드 샘플을 참조하세요.

use FacebookAds\Api;
use FacebookAds\Object\ServerSide\BatchProcessor;
use FacebookAds\Object\ServerSide\CustomData;
use FacebookAds\Object\ServerSide\Event;
use FacebookAds\Object\ServerSide\EventRequestAsync;
use FacebookAds\Object\ServerSide\UserData;

use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Promise;

$pixel_id = getenv('PIXEL_ID');
$access_token = getenv('ACCESS_TOKEN');

if (empty($pixel_id) || empty($access_token)) {
  throw new Exception('Missing required test config. Got pixel_id: "' . $pixel_id . '", access_token: "' . $access_token . '"');
}

$api = Api::init(null, null, $access_token, false);

function create_event($i) {
  $user_data = (new UserData())
    ->setEmail('joe' . $i . '@eg.com')
    ->setClientIpAddress($_SERVER['REMOTE_ADDR'])
    ->setClientUserAgent($_SERVER['HTTP_USER_AGENT']);

  $custom_data = (new CustomData())
    ->setCurrency('usd')
    ->setValue(123.45);

  return (new Event())
    ->setEventName('Purchase')
    ->setEventTime(time())
    ->setEventSourceUrl('http://jaspers-market.com/product/' . $i)
    ->setUserData($user_data)
    ->setCustomData($custom_data)
    ->setActionSource(ActionSource::WEBSITE);
}

function create_events($num) {
  $events = [];

  for ($i = 0; $i < $num; $i++) {
    $events[] = create_event($i);
  }

  return $events;
}

function create_async_requests($pixel_id, $num) {
  $requests = [];

  for ($i = 0; $i < $num; $i++) {
    $requests[] = (new EventRequestAsync($pixel_id))
      ->setUploadTag('test-tag-2')
      ->setEvents([create_event($i)]);
  }

  return $requests;
}

function run($pixel_id) {
  print("Started CONVERSIONS_API_EVENT_CREATE_BATCH...\n");
  $batch_processor = new BatchProcessor($pixel_id, 2, 2);

  // processEvents
  $events = create_events(11);
  $batch_processor->processEvents(array('upload_tag' => 'test-tag-1'), $events);

  // processEventRequests
  $requests = create_async_requests($pixel_id, 5);
  $batch_processor->processEventRequests($requests);

  // processEventsGenerator
  $process_events_generator = $batch_processor->processEventsGenerator(array('upload_tag' => 'test-tag-1'), $events);
  foreach ($process_events_generator as $promises) {
    try {
      Promise\unwrap($promises);
    } catch (RequestException $e) {
      print('RequestException: ' . $e->getResponse()->getBody()->getContents() . "\n");
      throw $e;
    } catch (\Exception $e) {
      print("Exception:\n");
      print_r($e);
      throw $e;
    }
  }

  // processEventRequestsGenerator
  $requests = create_async_requests($pixel_id, 5);
  $process_event_requests_generator = $batch_processor->processEventRequestsGenerator($requests);
  foreach ($process_event_requests_generator as $promises) {
    try {
      Promise\unwrap($promises);
    } catch (RequestException $e) {
      print('RequestException: ' . $e->getResponse()->getBody()->getContents() . "\n");
      throw $e;
    } catch (\Exception $e) {
      print("Exception:\n");
      print_r($e);
      throw $e;
    }
  }
  print("Finished CONVERSIONS_API_EVENT_CREATE_BATCH with no errors.\n");
}

run($pixel_id);
import asyncio
import time
import os
import sys
repo_dir = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)
sys.path.insert(1, repo_dir)

from facebook_business.adobjects.serverside.batch_processor import BatchProcessor
from facebook_business.adobjects.serverside.custom_data import CustomData
from facebook_business.adobjects.serverside.event import Event
from facebook_business.adobjects.serverside.event_request_async import EventRequestAsync
from facebook_business.adobjects.serverside.user_data import UserData
from facebook_business.api import FacebookAdsApi


def get_event(num):
    user_data = UserData(
        email="joe%s@eg.com" % num,
        client_ip_address=request.META.get('REMOTE_ADDR'),
        client_user_agent=request.headers['User-Agent']
    )
    custom_data = CustomData(currency="usd", value=123.45, item_number="itemnumber-123")
    event = Event(
        event_name="Purchase",
        event_time=int(time.time()),
        user_data=user_data,
        custom_data=custom_data,
        data_processing_options=[],
        event_source_url='http://jaspers-market.com/product/123',
        action_source=ActionSource.WEBSITE
    )
    return event

def get_events(num):
    events = []
    for i in range(num):
        events.append(get_event(num))
    return events

def get_event_requests_async(num):
    event_requests_async = []
    for i in range(num):
        event_requests_async.append(
            EventRequestAsync(
                events=[get_event(i)],
                pixel_id=pixel_id
            )
        )
    return event_requests_async

def run_process_event_requests():
    batch_processor = BatchProcessor(2, 2)
    event_requests_async = get_event_requests_async(3)
    batch_processor.process_event_requests(event_requests_async)

async def run_process_event_requests_generator():
    batch_processor = BatchProcessor(3, 2)
    event_requests_async = get_event_requests_async(7)
    generator = batch_processor.process_event_requests_generator(event_requests_async)
    async for batch_responses in generator:
        print(batch_responses)

def run_process_events():
    batch_processor = BatchProcessor(2, 2)
    event_request_async_to_clone = EventRequestAsync(pixel_id=pixel_id, events=[])
    events = get_events(3)
    batch_processor.process_events(event_request_async_to_clone, events)

async def run_process_events_generator():
    batch_processor = BatchProcessor(3, 2)
    event_request_async_to_clone = EventRequestAsync(pixel_id=pixel_id, events=[])
    events = get_events(10)
    generator = batch_processor.process_events_generator(event_request_async_to_clone, events)
    async for batch_responses in generator:
        print(batch_responses)

if __name__ == '__main__':
    pixel_id = os.getenv("PIXEL_ID")
    access_token = os.getenv("ACCESS_TOKEN")
    if not (pixel_id and access_token):
        raise Exception("Missing required test config. Got pixel_id: '{pixel_id}', access_token: '{access_token}'".format(
            pixel_id=pixel_id,
            access_token=access_token
        ))
    FacebookAdsApi.init(access_token=access_token, crash_log=False)

    run_process_event_requests()
    print("BatchProcessor process_event_requests - OK.")

    asyncio.run(run_process_event_requests_generator())
    print("BatchProcessor process_event_requests_generator - OK.")

    run_process_events()
    print("BatchProcessor process_events - OK.")

    asyncio.run(run_process_events_generator())
    print("BatchProcessor process_events_generator - OK.")
const bizSdk = require('facebook-nodejs-business-sdk');
const process = require('process');
const ServerEvent = bizSdk.ServerEvent;
const EventRequest = bizSdk.EventRequest;
const UserData = bizSdk.UserData;
const CustomData = bizSdk.CustomData;
const Content = bizSdk.Content;
const BatchProcessor = bizSdk.BatchProcessor;

const access_token = process.env.ACCESS_TOKEN;
const pixel_id = process.env.PIXEL_ID;

function createEvents(num) {
  let events = [];
  for (let i = 0; i < num; i++) {
    let current_timestamp = Math.floor(new Date() / 1000);

    const user_data = (new UserData())
      .setEmail(`joe${i}@eg.com`)
      .setClientIpAddress(request.connection.remoteAddress)
      .setClientUserAgent(request.headers['user-agent']);

    const custom_data = (new CustomData())
      .setCurrency('usd')
      .setCustomProperties({custom1: 'value2'})
      .setValue(123.45);

    const server_event = (new ServerEvent())
      .setEventName('Purchase')
      .setEventTime(current_timestamp)
      .setUserData(user_data)
      .setCustomData(custom_data)
      .setEventSourceUrl('http://jaspers-market.com/product/123')
      .setActionSource('website');

    events.push(server_event);
  }

  return events;
}

function createEventRequests(num, access_token, pixel_id) {
  let event_requests = [];
  for (let i = 0; i < num; i++) {
    const events = createEvents(2);
    const event_request = (new EventRequest(access_token, pixel_id))
      .setEvents(events);
    event_requests.push(event_request);
  }

  return event_requests;
}

void async function() {
  try {
    if (access_token === undefined || pixel_id === undefined) {
      throw new Error(`"Missing required test config. Got pixel_id: '${pixel_id}', access_token: '${access_token}'"`)
    }
    const api = bizSdk.FacebookAdsApi.init(access_token);

    const batch_processor = new BatchProcessor(2, 2);

    // processEvents
    const events1 = createEvents(5);
    const event_request = (new EventRequest(access_token, pixel_id));
    batch_processor.processEvents(event_request, events1);
    console.log('BatchProcessor.processEvents - OK.');

    // processEventRequests
    const event_requests1 = createEventRequests(3, access_token, pixel_id);
    batch_processor.processEventRequests(event_requests1);
    console.log('BatchProcessor.processEventRequests - OK.');

    // processEventsGenerator
    const events2 = createEvents(5);
    const eventsGenerator = batch_processor.processEventsGenerator(event_request, events2);
    while (true) {
      const batch = eventsGenerator.next().value;
      if (!batch || batch.length === 0) {
        eventsGenerator.return();
        break;
      }

      await Promise.all(batch).then(response => {
        console.log('processEventsGenerator Events Received: ', response.map(r => r.events_received))
      }).catch(response => {
        console.log('processEventsGenerator Error: ', response);
      });
    }

    // processEventRequestsGenerator
    const event_requests2 = createEventRequests(3, access_token, pixel_id);
    const eventRequestsGenerator = batch_processor.processEventRequestsGenerator(event_requests2);
    while (true) {
      const batch = eventRequestsGenerator.next().value;
      if (!batch || batch.length === 0) {
        eventRequestsGenerator.return();
        break;
      }

      await Promise.all(batch).then(response => {
        console.log('processEventRequestsGenerator Events Received: ', response.map(r => r.events_received))
      }).catch(response => {
        console.log('processEventRequestsGenerator Error: ', response);
      });
    }
  } catch(error) {
    console.log(error);
    process.exit(1);
  }
}();
import com.facebook.ads.sdk.APIContext;
import com.facebook.ads.sdk.serverside.*;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

class CONVERSIONS_API_EVENT_CREATE_BATCH {
  public static final String ACCESS_TOKEN = System.getenv("ACCESS_TOKEN");
  public static final String PIXEL_ID = System.getenv("PIXEL_ID");

  public static void run() throws Exception {
    if (ACCESS_TOKEN == null || PIXEL_ID == null) {
      throw new Exception(String.format("Missing required test config. Got pixel_id: '%s', access_token: '%s'", PIXEL_ID, ACCESS_TOKEN));
    }

    APIContext context = new APIContext(ACCESS_TOKEN);
    context.setLogger(System.out);

    BatchProcessor batchProcessor = new BatchProcessor(2, 3);

    List
require 'concurrent'
require 'facebook_ads'

def get_event(num)
    user_data = FacebookAds::ServerSide::UserData.new(
        email: 'joe#{num}@eg.com',
        client_ip_address: request.remote_ip,
        client_user_agent: request.user_agent
    )

    custom_data = FacebookAds::ServerSide::CustomData.new(
        currency: 'usd',
        value: 123.45
    )

    FacebookAds::ServerSide::Event.new(
        event_name: 'Purchase',
        event_time: Time.now.to_i,
        user_data: user_data,
        custom_data: custom_data,
        event_source_url: 'http://jaspers-market.com/product/123',
        action_source: 'website'
    )
end

def get_events(num)
    num.times.map do |i|
        get_event(i)
    end
end

def get_event_request_async(pixel_id, num)
    FacebookAds::ServerSide::EventRequestAsync.new(
        pixel_id: pixel_id,
        events: [get_event(num)]
    )
end

def get_event_requests_async(pixel_id, num)
    num.times.map do |i|
        get_event_request_async(pixel_id, i)
    end
end

def run_process_event_requests(pixel_id)
    batch_processor = FacebookAds::ServerSide::BatchProcessor.new(2, 2)
    event_requests_async = get_event_requests_async(pixel_id, 3)
    batch_processor.process_event_requests(event_requests_async)
end

def run_process_event_requests_generator(pixel_id)
    batch_processor = FacebookAds::ServerSide::BatchProcessor.new(3, 2)
    event_requests_async = get_event_requests_async(pixel_id, 7)
    generator = batch_processor.process_event_requests_generator(event_requests_async)
    generator.each do |batch|
        responses = Concurrent::Promise.zip(*batch).execute.value!
        print "#{responses}\n"
    end
end

def run_process_events(pixel_id)
    batch_processor = FacebookAds::ServerSide::BatchProcessor.new(2, 2)
    event_request_async_to_clone = FacebookAds::ServerSide::EventRequestAsync.new(pixel_id: pixel_id)
    events = get_events(3)
    batch_processor.process_events(event_request_async_to_clone, events)
end

def run_process_events_generator(pixel_id)
    batch_processor = FacebookAds::ServerSide::BatchProcessor.new(3, 2)
    event_request_async_to_clone = FacebookAds::ServerSide::EventRequestAsync.new(pixel_id: pixel_id)
    events = get_events(10)
    generator = batch_processor.process_events_generator(event_request_async_to_clone, events)
    generator.each do |batch|
        responses = Concurrent::Promise.zip(*batch).execute.value!
        print "#{responses}\n"
    end
end

def main
    access_token = ENV['ACCESS_TOKEN']
    pixel_id = ENV['PIXEL_ID']
    unless access_token && pixel_id
        raise Exception.new("Missing required test config. Got pixel_id: '#{pixel_id}', access_token: '#{access_token}'")
    end

    FacebookAds.configure do |config|
      config.access_token = access_token
    end

    run_process_event_requests(pixel_id)
    print "BatchProcessor process_event_requests - OK.\n"

    run_process_event_requests_generator(pixel_id)
    print "BatchProcessor process_event_requests_generator - OK.\n"

    run_process_events(pixel_id)
    print "BatchProcessor process_events - OK.\n"

    run_process_events_generator(pixel_id)
    print "BatchProcessor process_events_generator - OK.\n"
end

main

HTTP 서비스 인터페이스

HTTP 서비스 계층에 대한 특정 요구 사항이 있는 경우 HTTP 서비스 인터페이스를 사용하세요. 이 기능을 사용하면 Business SDK의 기본 HTTP 서비스를 재정의하고 원하는 메서드나 라이브러리를 사용하여 맞춤 서비스를 구현할 수 있습니다.

자체 HTTP 서비스 인터페이스를 구현하려면 다음 언어의 코드 샘플을 참조하세요.

require __DIR__ . '/../vendor/autoload.php';

use FacebookAds\Api;
use FacebookAds\Object\ServerSide\CustomData;
use FacebookAds\Object\ServerSide\Event;
use FacebookAds\Object\ServerSide\EventRequest;
use FacebookAds\Object\ServerSide\EventRequestAsync;
use FacebookAds\Object\ServerSide\HttpServiceClientConfig;
use FacebookAds\Object\ServerSide\UserData;

// Imports used by the TestHttpClient class
use FacebookAds\Object\ServerSide\HttpServiceInterface;
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Handler\CurlHandler;
use GuzzleHttp\Psr7\MultipartStream;
use GuzzleHttp\Psr7\Request;

$pixel_id = getenv('PIXEL_ID');
$access_token = getenv('ACCESS_TOKEN');

if (empty($pixel_id) || empty($access_token)) {
  throw new Exception('Missing required test config. Got pixel_id: "' . $pixel_id . '", access_token: "' . $access_token . '"');
}

function run($access_token, $pixel_id) {
  Api::init(null, null, $access_token, false);

  $request1 = getEventRequest($pixel_id, 1);
  $request1->setHttpClient(new TestHttpClient());

  $response1 = $request1->execute();

  print("Response: " . $response1->getBody() . "\n");
  print("Custom HTTP Service Request 1 - OK.\n");

  // Alternatively, you can set the access_token and the HTTP Client on the HttpServiceClientConfig
  Api::init(null, null, null, false);
  HttpServiceClientConfig::getInstance()->setClient(new TestHttpClient());
  HttpServiceClientConfig::getInstance()->setAccessToken($access_token);

  $request2 = getEventRequest($pixel_id, 2);

  $response2 = $request2->execute();

  print("Response: " . $response2->getBody() . "\n");
  print("Custom HTTP Service Request 2 - OK.\n");
}

function getEventRequest($pixel_id, $num) {
  $user_data = (new UserData())
    ->setEmail('joe' . $num . '@eg.com')
    ->setClientIpAddress($_SERVER['REMOTE_ADDR'])
    ->setClientUserAgent($_SERVER['HTTP_USER_AGENT']);

  $custom_data = (new CustomData())
    ->setCurrency('usd')
    ->setValue(123.45);

  $event = (new Event())
    ->setEventName('Purchase')
    ->setEventTime(time())
    ->setEventSourceUrl('http://jaspers-market.com/product/123')
    ->setUserData($user_data)
    ->setCustomData($custom_data)
    ->setActionSource(ActionSource::WEBSITE);

  return (new EventRequest($pixel_id))
    ->setEvents(array($event));
}

class TestHttpClient implements HttpServiceInterface {
  public function executeRequest($url, $method, array $curl_options, array $headers, array $params) {
    $multipart_contents = [];

    foreach ($params as $key => $value) {
      if ($key === 'data') {
        $multipart_contents[] = [
          'name' => $key,
          'contents' => \GuzzleHttp\json_encode($value),
          'headers' => array('Content-Type' => 'multipart/form-data'),
        ];
      } else {
        $multipart_contents[] = [
          'name' => $key,
          'contents' => $value,
          'headers' => array('Content-Type' => 'multipart/form-data'),
        ];
      }
    }

    $body = new MultipartStream($multipart_contents);
    $request = new Request($method, $url, $headers, $body);

    $handler_stack = HandlerStack::create(
      new CurlHandler(['options' => $curl_options])
    );

    $client = new Client(['handler' => $handler_stack]);
    return $client->send($request);
  }
}

run($access_token, $pixel_id);
import time
import os
import sys
repo_dir = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)
sys.path.insert(1, repo_dir)

from facebook_business.adobjects.serverside.custom_data import CustomData
from facebook_business.adobjects.serverside.event import Event
from facebook_business.adobjects.serverside.event_request import EventRequest
from facebook_business.adobjects.serverside.http_service_interface import HttpServiceInterface
from facebook_business.adobjects.serverside.user_data import UserData
from facebook_business.api import FacebookAdsApi


def run(pixel_id, access_token):
    user_data = UserData(
        email="joe@eg.com",
        client_ip_address=request.META.get('REMOTE_ADDR'),
        client_user_agent=request.headers['User-Agent']
    )
    custom_data = CustomData(currency="usd", value=123.45, item_number="itemnumber-123")
    event = Event(
        event_name="Purchase",
        event_time=int(time.time()),
        user_data=user_data,
        custom_data=custom_data,
        data_processing_options=[],
        event_source_url='http://jaspers-market.com/product/123',
        action_source=ActionSource.WEBSITE
    )
    custom_http_client = CustomHttpClient()
    event_request = EventRequest(
        events=[event],
        pixel_id=pixel_id,
        http_client=custom_http_client,
        access_token=access_token
    )

    event_response = event_request.execute()
    print(event_response)
    print("Custom HTTP Service Request - OK.")

class CustomHttpClient(HttpServiceInterface):
    def execute(self, url, method, request_options, headers, params):
        import requests
        from facebook_business.adobjects.serverside.event_response import EventResponse

        response = requests.request(method, url, json=params, headers=headers).json()
        return EventResponse(
            events_received=response['events_received'],
            fbtrace_id=response['fbtrace_id'],
            messages=response['messages']
        )

if __name__ == '__main__':
    pixel_id = os.getenv("PIXEL_ID")
    access_token = os.getenv("ACCESS_TOKEN")
    if not (pixel_id and access_token):
        raise Exception("Missing required test config. Got pixel_id: '{pixel_id}', access_token: '{access_token}'".format(
            pixel_id=pixel_id,
            access_token=access_token
        ))

    run(pixel_id, access_token)
const bizSdk = require('facebook-nodejs-business-sdk');
const https = require('https');
const process = require('process');
const ServerEvent = bizSdk.ServerEvent;
const EventRequest = bizSdk.EventRequest;
const EventResponse = bizSdk.EventResponse;
const UserData = bizSdk.UserData;
const CustomData = bizSdk.CustomData;
const Content = bizSdk.Content;

const access_token = process.env.ACCESS_TOKEN;
const pixel_id = process.env.PIXEL_ID;

// Implements the HttpServiceInterface
class E2EHttpService {
  executeRequest(url, method, headers, params) {
    return new Promise((resolve, reject) => {
      const options = {
        port: 443,
        method,
        headers,
      }
      let body = '';
      const request = https.request(url, options, response => {
        response.on('data', chunk => {
          body += chunk.toString();
        });
        response.on('end', () => {
          return resolve(body);
        });
      }).on('error', reject);

      request.write(JSON.stringify(params));
      request.end();
    });
  }
}

void async function() {
  try {
    if (access_token === undefined || pixel_id === undefined) {
      throw new Error(`"Missing required test config. Got pixel_id: '${pixel_id}', access_token: '${access_token}'"`)
    }
    const userData = (new UserData())
      .setEmail('joe@eg.com')
      .setClientIpAddress(request.connection.remoteAddress)
      .setClientUserAgent(request.headers['user-agent']);

    const customData = (new CustomData())
      .setCurrency('usd')
      .setCustomProperties({custom1: 'value2'})
      .setValue(123.45);

    const serverEvent = (new ServerEvent())
      .setEventName('Purchase')
      .setEventTime(Math.floor(new Date() / 1000))
      .setUserData(userData)
      .setCustomData(customData)
      .setEventSourceUrl('http://jaspers-market.com/product/123')
      .setActionSource('website');

    const eventsData = [serverEvent];
    const eventRequest = (new EventRequest(access_token, pixel_id))
      .setHttpService(new E2EHttpService())
      .setEvents(eventsData);

    eventRequest.execute().then(response => {
      console.log('Custom HTTP Service Request OK. Response: ', response);
    }, err => {
      console.log('Error: ', err);
    });
  } catch(error) {
    console.log(error);
    process.exit(1);
  }
}();
import com.facebook.ads.sdk.APIContext;
import com.facebook.ads.sdk.serverside.*;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

public class CONVERSIONS_API_EVENT_CREATE_CUSTOM_HTTP_SERVICE {
  public static final String ACCESS_TOKEN = System.getenv("ACCESS_TOKEN");
  public static final String PIXEL_ID = System.getenv("PIXEL_ID");

  public static void run() throws Exception {
    if (ACCESS_TOKEN == null || PIXEL_ID == null) {
      throw new Exception(String.format("Missing required test config. Got pixel_id: '%s', access_token: '%s'", PIXEL_ID, ACCESS_TOKEN));
    }

    APIContext context = new APIContext(ACCESS_TOKEN).enableDebug(true);
    context.setLogger(System.out);

    UserData userData = new UserData()
        .email("joe@eg.com")
        .clientIpAddress(clientIpAddress)
        .clientUserAgent(clientUserAgent);

    HashMap<String, String> customProperties = new HashMap<>();
    customProperties.put("item_number", "456");

    CustomData customData = new CustomData()
        .currency("usd")
        .customProperties(customProperties)
        .value(123.45F);

    Event pageViewEvent = new Event();
    pageViewEvent.eventName("Purchase")
        .eventTime(System.currentTimeMillis() / 1000L)
        .userData(userData)
        .customData(customData)
        .eventSourceUrl("http://jaspers-market.com/product/123")
        .actionSource(ActionSource.website);

    EventRequest eventRequest = new EventRequest(PIXEL_ID, context);
    eventRequest.addDataItem(pageViewEvent);

    // Set the Custom HTTP Service Client
    HttpServiceInterface httpServiceClient = new E2EHttpServiceClient();
    eventRequest.setHttpServiceClient(httpServiceClient);

    EventResponse eventResponse = eventRequest.execute();
    System.out.println("Request was successful:");
    System.out.println(eventResponse);
  }

  public static void main(String[] args) {
    try {
      run();
    } catch (Exception e) {
      e.printStackTrace();
      System.out.println(e.toString());
      System.exit(1);
    }
    System.exit(0);
  }

  private static class E2EHttpServiceClient implements HttpServiceInterface {
    @Override
    public EventResponse executeRequest(String url, HttpMethodEnum httpMethod, Map<String, String> headers, HttpServiceParams params) {
      EventResponse eventResponse = null;
      try {
        Gson gson = new GsonBuilder()
            .disableHtmlEscaping()
            .create();
        URL requestUrl = new URL(url);

        HttpURLConnection connection = (HttpURLConnection) requestUrl.openConnection();
        connection.setRequestMethod(httpMethod.toString());
        connection.setDoOutput(true);
        connection.setRequestProperty("Content-Type", "application/json");

        DataOutputStream out = new DataOutputStream(connection.getOutputStream());
        out.writeBytes(gson.toJson(params));
        out.flush();
        out.close();

        BufferedReader in = new BufferedReader(
            new InputStreamReader(connection.getInputStream())
        );
        String responseLine = in.readLine();
        StringBuffer response = new StringBuffer();
        while (responseLine != null) {
          response.append(responseLine);
          responseLine = in.readLine();
        }
        in.close();
        String responseString = response.toString();

        eventResponse = gson.fromJson(responseString, EventResponse.class);
      } catch (Exception e) {
        e.printStackTrace();
        System.exit(1);
      }
      return eventResponse;
    }
  }
}
require 'facebook_ads'

class CustomHttpClient < FacebookAds::ServerSide::HttpServiceInterface
    def execute(url, request_method, headers, params)
        require 'faraday'
        require 'json'

        raise Exception.new("Incorrect HTTP method: #{request_method}") if request_method != FacebookAds::ServerSide::HttpMethod::POST

        response = Faraday.post(url) do |request|
            headers.each do |key, value|
                request[key] = value
            end
            request.headers['Content-Type'] = 'application/json'
            request.body = params.to_json
        end

        parsed_response = JSON.load(response.body)

        return FacebookAds::ServerSide::EventResponse.new(
            events_received: parsed_response['events_received'],
            messages: parsed_response['messages'],
            fbtrace_id: parsed_response['fbtrace_id']
        )
    end
end

def main
    access_token = ENV['ACCESS_TOKEN']
    pixel_id = ENV['PIXEL_ID']
    unless access_token && pixel_id
        raise Exception.new("Missing required test config. Got pixel_id: '#{pixel_id}', access_token: '#{access_token}'")
    end

    FacebookAds.configure do |config|
        config.access_token = access_token
    end

    user_data = FacebookAds::ServerSide::UserData.new(
        email: 'joe@eg.com',
        client_ip_address: request.remote_ip,
        client_user_agent: request.user_agent
    )

    custom_data = FacebookAds::ServerSide::CustomData.new(
        currency: 'usd',
        value: 123.45
    )

    event = FacebookAds::ServerSide::Event.new(
        event_name: 'Purchase',
        event_time: Time.now.to_i,
        user_data: user_data,
        custom_data: custom_data,
        event_source_url: 'http://jaspers-market.com/product/123',
        action_source: 'website'
    )

    request = FacebookAds::ServerSide::EventRequest.new(
        pixel_id: pixel_id,
        events: [event],
        http_service_client: CustomHttpClient.new
    )

    response = request.execute
    print "Response: #{response}\n"
    print "Custom HTTP Service Request - OK."
end

main

이벤트 요청 테스트

test_event_code 매개변수를 사용하여 이벤트 요청을 테스트할 수 있습니다. 데이터 소스 > 픽셀 > 이벤트 테스트 탭의 이벤트 관리자에 있는 이벤트 테스트 도구로 이동하여 테스트 코드를 찾을 수 있습니다.

참고: 아래의 코드에 있는 샘플 값(TEST12345)을 이벤트 테스트 탭에서 얻은 테스트 코드로 바꿉니다.

...
$request = (new EventRequest($pixel_id))
    ->setTestEventCode('TEST12345')
    ->setEvents($events);

$response = $request->execute();
...
event_request = EventRequest(
    events=[event],
    test_event_code='TEST12345',
    pixel_id=pixel_id
)

result = event_request.execute()
...
    const eventRequest = (new EventRequest(access_token, pixel_id))
      .setTestEventCode('TEST12345')
      .setEvents(eventsData);

    eventRequest.execute().then(response => {
      console.log('Execute Request OK. Response: ', response);
    }, err => {
      console.log('Error: ', err);
    });
...
    EventRequest eventRequest = new EventRequest(PIXEL_ID, context);
    eventRequest.addDataItem(purchaseEvent);
    eventRequest.setTestEventCode("TEST12345");

    EventResponse response = eventRequest.execute();
...
request = FacebookAds::ServerSide::EventRequest.new(
    pixel_id: PIXEL_ID,
    test_event_code: 'TEST12345',
    events: [event]
)

response = request.execute

제한 사항

현재 Meta에서는 동시 일괄 처리 요청이나 비동기식 요청을 보낼 때 맞춤 HTTP 서비스 인터페이스 설정을 지원하지 않습니다.