Перейти к содержимому
Socialift
Разделы документации
Справочник SDK

Клиент Facebook: методы Graph API

Facebook — клиент Meta Graph API в Python SDK Socialift. Он получает пользовательский токен через Facebook Login (обычный scope или config_id в Facebook Login for Business), возвращает управляемые страницы вместе с их токенами, публикует посты и истории, модерирует комментарии, подписывает страницу на вебхуки и читает лиды из форм Lead Ads. Токен передаётся в каждый метод аргументом и не хранится в клиенте.

from socialift import FacebookМетодов: 25по версии socialift 1.3.0Обновлено:

Как настроить клиент Facebook?

Клиент создаётся так: Facebook(app_id=..., app_secret=...). Оба значения обязательны — при пустом значении будет ConfigurationError. Facebook.from_env() берёт их из FACEBOOK_APP_ID и FACEBOOK_APP_SECRET, необязательный config_id — из FACEBOOK_CONFIG_ID, а версию Graph API — из META_GRAPH_VERSION (иначе используется версия SDK по умолчанию).

App ID и App Secret находятся в настройках приложения в Meta for Developers — пошагово в руководстве «Настройка приложения Meta». Для приложения типа Business (Facebook Login for Business) разрешения выбираются в конфигурации в App Dashboard, а в ссылку входа передаётся config_id; в остальных случаях отправляется список scopes. Ключи можно сохранить и проверить у провайдера в разделе кабинета «Ключи».

Типы токенов: me, pages, granted_scopes и revoke работают с пользовательским токеном; методы постов, комментариев, вебхуков и лидов — с токеном страницы Page.access_token, который возвращает pages(). appsecret_proof добавляется к каждому запросу автоматически.

Лицензионный ключ берётся из переменной SOCIALIFT_LICENSE_KEY или аргумента license_key=. Используйте клиент через async with, чтобы HTTP-сессия гарантированно закрывалась.

python
import asyncio
import os

from socialift import Facebook

async def main():
    # 1) Явные аргументы
    fb = Facebook(
        app_id=os.environ["FACEBOOK_APP_ID"],
        app_secret=os.environ["FACEBOOK_APP_SECRET"],
        config_id=os.environ.get("FACEBOOK_CONFIG_ID"),  # Login for Business
    )
    # 2) Или из окружения: FACEBOOK_APP_ID, FACEBOOK_APP_SECRET,
    #    FACEBOOK_CONFIG_ID, META_GRAPH_VERSION
    # fb = Facebook.from_env()

    async with fb:
        user_token = os.environ["FB_USER_TOKEN"]  # результат exchange_code()
        for page in await fb.pages(user_token):
            print(page.id, page.name, page.instagram_username)

asyncio.run(main())

Клиент и OAuth

Создание клиента, ссылка Facebook Login, обмен токена, проверка и отзыв разрешений.

exchange_codefrom_envgranted_scopeslogin_urlrevoke

Обменивает code из callback на краткосрочный, а затем сразу на долгосрочный пользовательский токен и возвращает TokenBundle. Вызывается один раз в OAuth callback.

await fb.exchange_code(code: str, *, redirect_uri: str) -> socialift.models.TokenBundle
  • redirect_uri должен в точности совпадать со значением из ссылки входа (требование Meta).
  • По документации Meta долгосрочный пользовательский токен обычно действует около 60 дней; срок берите из TokenBundle.expires_at, хранение токена — на вашей стороне.
  • Если Meta не вернула токен, будет ApiError.

from_env

classmethod

Создаёт клиент из переменных окружения: FACEBOOK_APP_ID, FACEBOOK_APP_SECRET, FACEBOOK_CONFIG_ID и META_GRAPH_VERSION. Подходит для серверных приложений, где ключи не должны лежать в коде.

Facebook.from_env(**kwargs) -> Facebook
  • Если FACEBOOK_APP_ID или FACEBOOK_APP_SECRET пусты, будет ConfigurationError.
  • Дополнительные аргументы (timeout, retry, session, license_key) передаются в конструктор.

Возвращает разрешения, реально выданные токену, через debug_token. Пользователь может отклонить часть разрешений в диалоге, поэтому включайте функции по этому списку, а не по запрошенному.

await fb.granted_scopes(token: str) -> list[str]
  • Запрос подписывается токеном приложения (app_id|app_secret); в аргумент передайте проверяемый токен.
  • Если разрешений нет, возвращается пустой список.

Формирует ссылку на диалог Facebook Login для редиректа пользователя; метод синхронный и запросов не отправляет. При наличии config_id (в аргументе или клиенте) используется Facebook Login for Business, иначе — список scopes.

fb.login_url(
    *,
    redirect_uri: str,
    state: Optional[str] = None,
    config_id: Optional[str] = None,
    scopes: Optional[list[str]] = None,
) -> str
  • SDK не хранит state: сгенерируйте случайное значение (например, secrets.token_urlsafe(32)), сохраните в сессии и сравните в callback — Meta описывает его как защиту от CSRF.
  • При config_id параметр scope не отправляется: разрешения берутся из конфигурации в App Dashboard. Login for Business работает только в приложениях типа Business.
Пример — python
url = fb.login_url(redirect_uri="https://siz.uz/cb", state=state, config_id="...")

revoke

async

Отзывает все разрешения приложения на стороне Facebook (DELETE /{user_id}/permissions) и возвращает bool. Вызывайте при отключении интеграции — просто удалить токен из базы недостаточно.

await fb.revoke(token: str, *, user_id: str = 'me') -> bool
  • По документации Meta после отзыва всех разрешений токены пользователя аннулируются, и ему нужно войти заново.
  • Вызывается с пользовательским токеном; user_id по умолчанию me.
Пример — python
await fb.revoke(user_token)

Профиль и страницы

Профиль пользователя и список страниц с их токенами.

mepages

me

async

Возвращает профиль владельца токена в виде Profile: id, имя, фото и email. Нужен сразу после входа, чтобы понять, кто подключился.

await fb.me(token: str) -> socialift.models.Profile
  • Нужен пользовательский токен, а не токен страницы.
  • email может быть пустым; полный ответ — в Profile.raw.

pages

async

Возвращает страницы, которыми управляет пользователь, в виде объектов Page: у каждой есть токен страницы (access_token) и связанный профессиональный аккаунт Instagram (instagram_id, instagram_username). Отсюда берётся токен для методов постов, комментариев, вебхуков и лидов.

await fb.pages(token: str) -> list[socialift.models.Page]
  • Вызывается с пользовательским токеном.
  • По документации Meta токен страницы, полученный с долгосрочным пользовательским токеном, не имеет срока действия и аннулируется только при определённых условиях.
  • Page.access_token секретен: не отдавайте его во фронтенд и не пишите в логи (в repr он скрыт).
  • Пагинация автоматическая, не более 500 страниц.

Нужные разрешения:pages_show_list

Пример — python
for page in await fb.pages(user_token):
    print(page.name, page.instagram_username)

Подписка на вебхуки

Подписка страницы на вебхуки приложения, проверка и отписка.

subscribe_pagesubscriptionsunsubscribe_page

Подписывает страницу на вебхуки приложения (POST /{page_id}/subscribed_apps). Даже при настроенном вебхуке на уровне приложения события со страницы не приходят, пока она не подписана.

await fb.subscribe_page(
    page_id: str,
    page_token: str,
    fields: Optional[list[str]] = None,
) -> bool
  • Нужен токен страницы; Meta требует разрешения pages_manage_metadata и pages_show_list.
  • Без fields отправляется список по умолчанию: leadgen, leadgen_update, feed, messages, messaging_postbacks, mention. Для поля messages Meta требует ещё pages_messaging — если его нет, передайте fields явно.
  • Правило Meta: вебхуки Instagram через subscribed_fields не настраиваются.

Нужные разрешения:pages_manage_metadata

Пример — python
await fb.subscribe_page(page_id, page_token, fields=["leadgen", "feed"])

Возвращает, на какие приложения и поля подписана страница. Используйте для диагностики, когда события вебхука перестали приходить.

await fb.subscriptions(page_id: str, page_token: str) -> list[dict]
  • Вызывается с токеном страницы; возвращается массив data из ответа Graph API без изменений.
Пример — python
apps = await fb.subscriptions(page_id, page_token)

Удаляет подписку приложения на вебхуки страницы (DELETE /{page_id}/subscribed_apps) и возвращает bool. Вызывайте, когда клиент отключает страницу.

await fb.unsubscribe_page(page_id: str, page_token: str) -> bool
  • После отписки лиды, комментарии и другие события с этой страницы приходить перестают.
Пример — python
await fb.unsubscribe_page(page_id, page_token)

Посты и статистика

Чтение, публикация и удаление постов страницы, статистика поста.

delete_postpost_insightspostspublish_post

Безвозвратно удаляет пост страницы (DELETE /{post_id}) и возвращает bool.

await fb.delete_post(post_id: str, page_token: str) -> bool
  • Нужен токен страницы; post_id — это id из posts() или publish_post().

Нужные разрешения:pages_manage_posts

Пример — python
await fb.delete_post(post_id, page_token)

Возвращает статистику поста как словарь {метрика: значение}. SDK запрашивает post_impressions, post_impressions_unique, post_engaged_users, post_clicks и post_reactions_by_type_total.

await fb.post_insights(post_id: str, page_token: str) -> dict[str, Any]
  • При ошибке API исключение не выбрасывается — возвращается пустой словарь {} (например, у старого поста нет статистики).
  • Meta отключила post_impressions для всех версий API с 15 ноября 2025 года, post_impressions_unique тоже в списке устаревших (замены: post_media_view, post_total_media_view_unique). На устаревшую метрику Graph API отвечает ошибкой, поэтому метод может вернуть {}.
  • Нужен токен страницы; Meta требует read_insights и pages_read_engagement.

Нужные разрешения:read_insightspages_read_engagement

Пример — python
stats = await fb.post_insights(post_id, page_token)

posts

async

Читает опубликованные посты страницы через /published_posts. /feed не используется, потому что туда попадают и записи других людей на странице.

await fb.posts(page_id: str, page_token: str, *, limit: int = 25) -> list[dict]
  • Вызывается с токеном страницы.
  • limit — общее число возвращаемых постов; пагинацию SDK проходит сам.
  • По документации Meta endpoint возвращает примерно 600 постов за год.

Нужные разрешения:pages_read_engagement

Пример — python
posts = await fb.posts(page_id, page_token, limit=25)

Публикует от имени страницы текстовый пост (при необходимости со ссылкой) в /{page_id}/feed и возвращает ответ Meta с id поста. published=False отправляет published=false — пост не публикуется сразу.

await fb.publish_post(
    page_id: str,
    page_token: str,
    *,
    message: str,
    link: Optional[str] = None,
    published: bool = True,
) -> dict
  • Нужен токен страницы. В руководстве Pages API Meta указаны разрешения pages_manage_posts, pages_manage_engagement, pages_read_engagement и задачи CREATE_CONTENT, MANAGE, MODERATE на странице.
  • Только текст и ссылка: загрузки фото или видео в этом методе нет.
  • scheduled_publish_time не отправляется, так что это не отложенная публикация.

Нужные разрешения:pages_manage_postspages_read_engagement

Пример — python
post = await fb.publish_post(page_id, page_token, message="Salom!", link="https://siz.uz")

Истории страницы

Публикация фото- и видеоисторий, список историй, статус загрузки видео. История живёт 24 часа.

publish_photo_storypublish_video_storystoriesvideo_story_status

Публикует фото как историю страницы и возвращает {photo_id, post_id, success}. Два шага: фото сначала загружается в POST /{page-id}/photos с published=false, затем полученный photo_id передаётся в edge photo_stories.

await fb.publish_photo_story(
    page_id: str,
    page_token: str,
    *,
    photo_url: Optional[str] = None,
    photo_id: Optional[str] = None,
) -> dict
  • Meta принимает в photo_stories только photo_id и не принимает ссылку — поэтому первый шаг обязателен; SDK делает его сам.
  • Передаётся ровно один из photo_url (публичная ссылка, файл скачивает Meta) и photo_id (уже загруженное неопубликованное фото). Если второй шаг оборвался, с photo_id можно продолжить без повторной загрузки.
  • Требования Meta: .jpeg, .bmp, .png, .gif или .tiff, до 10 МБ (для .png рекомендуется 1 МБ). Медиа из прошлого поста переиспользовать нельзя — для каждой истории нужна новая загрузка.
  • Неопубликованное фото хранится на серверах Facebook около 24 часов: столько же действует photo_id.
  • Разрешения: pages_manage_posts, pages_read_engagement, pages_show_list и задача CREATE_CONTENT на странице. Вызывается с токеном страницы.

Нужные разрешения:pages_manage_postspages_read_engagementpages_show_list

Пример — python
story = await fb.publish_photo_story(page_id, page_token,
                                        photo_url="https://cdn.siz.uz/story.jpg")

Публикует видео как историю страницы и возвращает {video_id, post_id, success}. Meta требует здесь трёхфазную «resumable upload»: upload_phase=start → загрузка файла на upload_url из ответа → upload_phase=finish.

await fb.publish_video_story(
    page_id: str,
    page_token: str,
    *,
    video_url: Optional[str] = None,
    video: Union[bytes, bytearray, str, os.PathLike, NoneType] = None,
    wait_timeout: float = 300.0,
    upload_attempts: int = 3,
) -> dict
  • Передаётся ровно один из video_url (публичная ссылка — файл скачивает Meta) и video (байты или путь к локальному файлу).
  • upload_url берётся из ответа и не изменяется (он ведёт на rupload.facebook.com); на втором шаге токен уходит не в query, а в заголовке Authorization: OAuth.
  • Если загрузка оборвалась, Meta сообщает, сколько байт дошло, и SDK продолжает с этого места — до upload_attempts попыток (по умолчанию 3), не отправляя файл заново.
  • Перед третьим шагом SDK ждёт статуса загрузки complete до wait_timeout (по умолчанию 300 секунд). По истечении времени будет ApiError, в payload которого остаётся video_id — состояние можно проверить через video_story_status().
  • Требования Meta (SDK их не проверяет): .mp4, кодек H.264 или H.265, звук AAC 48 кГц; соотношение 9:16, размер от 540x960 до 1080x1920, 24–60 FPS. По длительности в документации Meta встречаются два разных ограничения (3–90 с и «не длиннее 60 секунд») — безопасно держаться 3–60 секунд.
  • Ошибка о низком качестве файла (например «Resolution too low») приходит не на третьем шаге, а в статусе после загрузки; полный текст сохраняется в ApiError.payload.

Нужные разрешения:pages_manage_postspages_read_engagementpages_show_list

Пример — python
story = await fb.publish_video_story(page_id, page_token,
                                        video_url="https://cdn.siz.uz/story.mp4")

stories

async

Возвращает истории страницы: в каждой записи post_id, status, creation_time, media_type, media_id и url. post_id из publish_photo_story()/publish_video_story() соответствует записи в этом списке — так опубликованную историю можно отследить.

await fb.stories(page_id: str, page_token: str, *, limit: int = 25) -> list[dict]
  • SDK намеренно не отправляет fields: выбор полей для этого edge Meta не документирует, а неизвестный fields роняет в Graph API весь запрос.
  • Архивные истории возвращаются, только если на странице включён архив.
  • Разрешения: pages_read_engagement и pages_show_list; вызывается с токеном страницы.

Нужные разрешения:pages_read_engagementpages_show_list

Пример — python
stories = await fb.stories(page_id, page_token, limit=25)

Возвращает статус загрузки и обработки видеоистории (GET /{video-id}?fields=status): uploading_phase, processing_phase и publishing_phase, в каждой — status: not_started, in_progress, complete или error.

await fb.video_story_status(video_id: str, page_token: str) -> dict
  • На фазе загрузки есть дополнительное поле bytes_transfered (орфография из документации Meta) — оно показывает, с какого места продолжать прерванную загрузку.
  • Если publish_video_story() завершился ApiError, video_id остаётся в payload исключения: именно этим методом выясняют, что пошло не так.
  • Вызывается с токеном страницы.

Комментарии

Чтение комментариев к постам, ответы и скрытие.

commentshide_commentreply_comment

Возвращает комментарии к посту, начиная с новых (order=reverse_chronological). Подходит для очереди модерации или выгрузки комментариев в CRM.

await fb.comments(post_id: str, page_token: str, *, limit: int = 50) -> list[dict]
  • Нужен токен страницы. По документации Meta для получения ID комментариев к посту страницы нужны права модератора на этой странице.
  • filter не передаётся, поэтому действует значение Graph API по умолчанию: только комментарии верхнего уровня, без ответов.
  • limit — общее число комментариев; пагинация автоматическая.

Нужные разрешения:pages_read_engagement

Пример — python
comments = await fb.comments(post_id, page_token, limit=50)

Скрывает комментарий (is_hidden=true) или снова показывает его при hidden=False. Обратимая альтернатива удалению.

await fb.hide_comment(comment_id: str, page_token: str, hidden: bool = True) -> dict
  • По документации Meta is_hidden применим только к комментариям страниц.
  • Вызывается с токеном страницы.

Нужные разрешения:pages_manage_engagement

Пример — python
await fb.hide_comment(comment_id, page_token, hidden=True)

Отвечает на комментарий от имени страницы (POST /{comment_id}/comments) и возвращает id нового комментария.

await fb.reply_comment(comment_id: str, page_token: str, message: str) -> dict
  • По документации Meta нужен токен страницы пользователя, который может выполнять задачу MODERATE, и разрешение pages_manage_engagement.

Нужные разрешения:pages_manage_engagement

Пример — python
await fb.reply_comment(comment_id, page_token, "Rahmat!")

Lead Ads

Формы лидов, лиды и контекст рекламы, из которой пришёл лид.

ad_contextleadlead_formsleads

Возвращает контекст рекламы, из которой пришёл лид: ID и названия объявления, группы объявлений и кампании, objective, optimization_goal и targeting. Полезно, чтобы показать источник лида в CRM.

await fb.ad_context(ad_id: Optional[str], token: str) -> dict
  • Исключений не выбрасывает: при ошибке API (например, без ads_management) или пустом ad_id возвращает {}.
  • Ключи: ad_id, ad_name, adset_id, adset_name, campaign_id, campaign_name, objective, optimization_goal, targeting.

Нужные разрешения:ads_management

Пример — python
context = await fb.ad_context(ad_id, token)

lead

async

Возвращает один полный лид по leadgen_id из события вебхука leadgen в виде Lead. Основной способ передавать лиды в CRM в реальном времени.

await fb.lead(leadgen_id: str, page_token: str) -> socialift.models.Lead
  • Вебхук Meta содержит только идентификаторы (leadgen_id, page_id, form_id, adgroup_id, ad_id, created_time) — ответы формы получаются этим методом.
  • Нужны токен страницы и разрешение leads_retrieval.

Возвращает формы Lead Ads страницы в виде списка LeadForm: название, статус, язык, вопросы и число лидов. Нужен, чтобы выбрать форму и сопоставить вопросы с полями CRM.

await fb.lead_forms(page_id: str, page_token: str) -> list[socialift.models.LeadForm]
  • Нужен токен страницы; пагинация автоматическая, сырой ответ — в LeadForm.raw.

Нужные разрешения:leads_retrievalpages_manage_ads

Пример — python
forms = await fb.lead_forms(page_id, page_token)

leads

async

Возвращает лиды одной формы в виде списка Lead. С since (unix timestamp) можно забрать только более новые лиды — например, догрузить период, пропущенный вебхуком.

await fb.leads(
    form_id: str,
    page_token: str,
    *,
    since: Optional[int] = None,
    limit: int = 200,
) -> list[socialift.models.Lead]
  • since отправляется в Graph API как фильтр GREATER_THAN по time_created.
  • Lead.fields — нормализованные поля (full_name, email, phone и т. д.), Lead.field_data — исходный список от Meta.
  • По документации Meta для чтения лидов нужны leads_retrieval, ads_management, pages_show_list, pages_read_engagement, pages_manage_ads и токен человека, который может размещать рекламу в рекламном аккаунте.
  • limit по умолчанию 200; пагинация автоматическая.

Нужные разрешения:leads_retrieval

Пример — python
leads = await fb.leads(form_id, page_token, limit=200)
for lead in leads:
    print(lead.fields.get("phone"), lead.campaign_name)

Общие методы всех клиентов

У каждого HTTP-клиента (Telegram, Facebook, Instagram, LinkedIn, TikTok, Ads) есть эти низкоуровневые методы: чтобы вызвать эндпоинт, для которого в SDK ещё нет обёртки, или читать данные постранично. По завершении блока async with соединение закрывается автоматически.

request

async

Отправляет произвольный HTTP-запрос и возвращает JSON-ответ — для эндпоинта, у которого в SDK пока нет отдельного метода. Токен и параметры подписи (access_token, для Meta — appsecret_proof через socialift.crypto.appsecret_proof) вы передаёте сами в params или headers.

await fb.request(
    method: str,
    url: str,
    *,
    params: Optional[Mapping[str, Any]] = None,
    data: Optional[Any] = None,
    json: Optional[Any] = None,
    headers: Optional[Mapping[str, str]] = None,
) -> Any
  • Значения None в params не отправляются.
  • При лимите (RateLimitError) и временных ошибках сервера (HTTP 429, 500, 502, 503, 504) запрос повторяется по RetryPolicy; если есть заголовок Retry-After, SDK ждёт указанное время. Обрыв сети выбрасывается как TransportError.

get

async

Короткая форма request("GET", ...).

await fb.get(url: str, **kw) -> Any

post

async

Короткая форма request("POST", ...).

await fb.post(url: str, **kw) -> Any

delete

async

Короткая форма request("DELETE", ...).

await fb.delete(url: str, **kw) -> Any

Проходит по курсорной пагинации Meta (paging.next) и возвращает все элементы data одним списком.

await fb.paginate(
    url: str,
    *,
    params: Optional[Mapping[str, Any]] = None,
    max_items: int = 500,
    page_size: int = 100,
) -> list[dict]
  • max_items (по умолчанию 500) — защитный предел: у крупного аккаунта могут быть десятки тысяч записей. page_size — limit одного запроса.

close

async

Закрывает HTTP-сессию, созданную самим SDK (переданную извне сессию не трогает). При использовании async with Client(...) вызывается автоматически.

await fb.close() -> None

Частые вопросы

Как получить токен страницы Facebook (page access token)?

Отправьте пользователя в Facebook Login по ссылке из login_url и в callback обменяйте code на долгосрочный пользовательский токен через exchange_code. Затем pages(user_token) вернёт Page.access_token для каждой страницы. По документации Meta токен страницы, полученный с долгосрочным пользовательским токеном, не имеет срока действия и аннулируется только при определённых условиях.

Почему на вебхук не приходят лиды или комментарии?

Настройки вебхука на уровне приложения недостаточно: каждую страницу нужно отдельно подписать на приложение через subscribe_page. Проверить подписку можно методом subscriptions. Meta требует разрешение pages_manage_metadata, а для поля messages — ещё и pages_messaging.

Как получить лиды Facebook Lead Ads на Python?

Событие вебхука leadgen содержит только идентификаторы (leadgen_id, form_id, ad_id и другие). Полные ответы получите через lead(leadgen_id, page_token), а пропущенный период догрузите через leads(form_id, page_token, since=...). В Lead.fields лежат нормализованные поля: имя, телефон, email.

Что такое config_id в Facebook Login for Business?

В приложении типа Business разрешения выбираются не через scope в коде, а в конфигурации в Meta App Dashboard, и её ID передаётся в ссылку входа как config_id. Если в SDK задан config_id (в клиенте или в login_url), параметр scope не отправляется.

Как опубликовать историю на странице Facebook через API?

Фото публикуется в два шага: publish_photo_story(page_id, page_token, photo_url=...) сначала загружает фото с published=false, а затем передаёт полученный photo_id в edge photo_stories — ссылку Meta там не принимает, только photo_id. Для видео нужна трёхфазная загрузка (открыть сессию → залить файл на выданный Meta upload_url → опубликовать), её выполняет publish_video_story(). Разрешения: pages_manage_posts, pages_read_engagement, pages_show_list и задача CREATE_CONTENT на странице.

Поддерживает ли Socialift SDK Facebook Messenger?

Нет. В клиенте Facebook нет методов для чтения или отправки сообщений Messenger. Для Instagram Direct используйте методы conversations и send_message клиента Instagram.

Источники

  1. Meta: Long-lived access tokens
  2. Meta: Facebook Login for Business
  3. Meta: Webhooks for Pages
  4. Meta: Pages API — Posts
  5. Meta: Page Stories API
  6. Meta: Retrieving leads
  7. Meta: Deprecated Page Insights metrics

Связанные страницы