defmodule MessengerBot do @moduledoc """ MessengerBot Client """ alias MessengerBot.Config alias MessengerBot.Client.Base, as: Client alias MessengerBot.Util.Encryption @typedoc """ Facebook App ID """ @type app_id :: String.t() @typedoc """ Facebook Page ID """ @type page_id :: String.t() @typedoc """ User's page-scoped ID or app-scoped ID. """ @type user_id :: integer() | String.t() @typedoc """ User profile field list """ @type user_profile_fields :: list(String.t()) @typedoc """ Metric list """ @type metrics :: list(String.t()) @typedoc """ Pagination cursor value from previous calls, can be nil """ @type cursor :: {:after, String.t()} | {:before, String.t()} | {} @typedoc """ Reference for Facebook Page data Using page_ref, MessengerBot client access to the page token and app secret data from the configuration. """ @type page_ref :: {app_id(), page_id()} @typedoc """ Optional request transaction identifier. This value is passed is passed into EventBus Event struct. It is usually used to track events in the same transaction. For example; when you send batch messages to an audience, you can track which messages delivered in the same transaction. Or while setting a Messenger Profile, you may need to make series of requests to complete the page setup. You can use same tx_id to trace sequential related events. """ @type tx_id :: String.t() @typedoc """ API call execution result Successful HTTP requests will return tuple of `:ok` with response body as Map. Unsuccessful HTTP requests will return tuple of `:error` with response body as Map. For HTTP client errors, it will return tuple of `{:error, %{error: reason}}`, where `reason` is an error tuple of `Tesla` dependency. """ @type res :: {:ok, Map.t()} | {:error, Map.t()} ############################################################################ # Attachment Upload API # ############################################################################ @doc """ Attachment Upload API ## Examples iex> attachment = %{type: "image", payload: %{url: "...", is_reusable: true}} iex> MessengerBot.upload_attachment({"", ""}, attachment) {:ok, %{"attachment_id" => "1857777774821032"}} """ @spec upload_attachment(page_ref(), Map.t()) :: res() @spec upload_attachment(page_ref(), Map.t(), tx_id()) :: res() def upload_attachment({app_id, page_id}, %{} = attachment, tx_id \\ nil) do Client.rpost( "/me/message_attachments", %{message: %{attachment: attachment}}, {app_id, page_id, :mb_attachment_upload, tx_id} ) end ############################################################################ # Broadcast API # ############################################################################ @doc """ Broadcast API / create_message_creatives ## Examples iex> messages = [%{}] iex> MessengerBot.create_message_creative({"", ""}, messages) {:ok, %{"message_creative_id" => 938461089}} """ @spec create_message_creative(page_ref(), list(Map.t())) :: res() @spec create_message_creative(page_ref(), list(Map.t()), tx_id()) :: res() def create_message_creative({app_id, page_id}, messages, tx_id \\ nil) do Client.rpost( "/me/create_message_creatives", %{messages: messages}, {app_id, page_id, :mb_create_message_creatives, tx_id} ) end @doc """ Broadcast API / broadcast_message ## Examples iex> message_ref = %{message_creative_id: 938461089} iex> MessengerBot.broadcast_message({"", ""}, message_ref) {:ok, %{"broadcast_id" => 827}} """ @spec broadcast_message(page_ref(), Map.t()) :: res() @spec broadcast_message(page_ref(), Map.t(), tx_id()) :: res() def broadcast_message({app_id, page_id}, %{} = message_ref, tx_id \\ nil) do Client.rpost( "/me/broadcast_messages", message_ref, {app_id, page_id, :mb_broadcast_message, tx_id} ) end ############################################################################ # Handover Protocol API # ############################################################################ @doc """ Handover Protocol API / pass_thread_control """ @spec pass_thread_control(page_ref(), Map.t()) :: res() @spec pass_thread_control(page_ref(), Map.t(), tx_id()) :: res() def pass_thread_control({app_id, page_id}, %{} = req, tx_id \\ nil) do Client.rpost( "/me/pass_thread_control", req, {app_id, page_id, :mb_pass_thread_control, tx_id} ) end @doc """ Handover Protocol API / take_thread_control """ @spec take_thread_control(page_ref(), Map.t()) :: res() @spec take_thread_control(page_ref(), Map.t(), tx_id()) :: res() def take_thread_control({app_id, page_id}, %{} = req, tx_id \\ nil) do Client.rpost( "/me/take_thread_control", req, {app_id, page_id, :mb_take_thread_control, tx_id} ) end @doc """ Handover Protocol API / request_thread_control """ @spec request_thread_control(page_ref(), Map.t()) :: res() @spec request_thread_control(page_ref(), Map.t(), tx_id()) :: res() def request_thread_control({app_id, page_id}, %{} = req, tx_id \\ nil) do Client.rpost( "/me/request_thread_control", req, {app_id, page_id, :mb_request_thread_control, tx_id} ) end @doc """ Handover Protocol API / secondary_receivers """ @spec fetch_secondary_receivers(page_ref(), Map.t()) :: res() @spec fetch_secondary_receivers(page_ref(), Map.t(), tx_id()) :: res() def fetch_secondary_receivers({app_id, page_id}, fields, tx_id \\ nil) do Client.rget( "/me/secondary_receivers", [fields: fields], {app_id, page_id, :mb_fetch_secondary_receivers, tx_id} ) end ############################################################################ # ID Matching API # ############################################################################ @doc """ ID Matching API / ids_for_page ## Examples iex> user_id = 1234567890 iex> cursor = nil iex> MessengerBot.fetch_ids_for_page({"", ""}, {user_id, cursor}) {:ok, %{"data" => [%{"id" => "1429374444444138", }], "paging" => %{}}} """ @spec fetch_ids_for_page(page_ref(), {user_id(), cursor()}) :: res() @spec fetch_ids_for_page(page_ref(), {user_id(), cursor()}, tx_id()) :: res() def fetch_ids_for_page({app_id, page_id}, {user_id, cursor}, tx_id \\ nil) do params = [ page: page_id, appsecret_proof: app_secret_proof({app_id, page_id}) ] query_params = if is_nil(cursor), do: params, else: [cursor | params] Client.rget( "/#{user_id}/ids_for_pages", query_params, {app_id, page_id, :mb_id_matching, tx_id} ) end @doc """ ID Matching API / ids_for_app ## Examples iex> user_id = 1234567890 iex> cursor = {:after, "NjgyNDk4MTcxOTQzMTY1"} iex> MessengerBot.fetch_ids_for_app({"", ""}, {user_id, cursor}) {:ok, %{"data" => [%{"id" => "1429374444444138", }], "paging" => %{}}} """ @spec fetch_ids_for_app(page_ref(), {user_id(), cursor()}) :: res() @spec fetch_ids_for_app(page_ref(), {user_id(), cursor()}, tx_id()) :: res() def fetch_ids_for_app({app_id, page_id}, {user_id, cursor}, tx_id \\ nil) do params = [ app: app_id, appsecret_proof: app_secret_proof({app_id}) ] query_params = if is_nil(cursor), do: params, else: [cursor | params] Client.rget( "/#{user_id}/ids_for_apps", query_params, {app_id, page_id, :mb_id_matching, tx_id} ) end ############################################################################ # Messenger Code API # ############################################################################ @doc """ Messenger Code API ## Examples iex> req = %{type: "standard", data: %{ref: "ads"}, image_size: 1000} iex> MessengerBot.create_messenger_code({"", ""}, req) {:ok, %{"uri" => "..."}} """ @spec create_messenger_code(page_ref(), Map.t()) :: res() @spec create_messenger_code(page_ref(), Map.t(), tx_id()) :: res() def create_messenger_code({app_id, page_id}, %{} = req, tx_id \\ nil) do Client.rpost( "/me/messenger_codes", req, {app_id, page_id, :mb_create_messenger_code, tx_id} ) end ############################################################################ # Messaging Feature Review API # ############################################################################ @doc """ Messaging Feature Review API ## Examples iex> MessengerBot.fetch_messaging_feature_review({"", ""}) {:ok, %{"data" => [%{feature: "...", status: "..."}, ]}} """ @spec fetch_messaging_feature_review(page_ref()) :: res() @spec fetch_messaging_feature_review(page_ref(), tx_id()) :: res() def fetch_messaging_feature_review({app_id, page_id}, tx_id \\ nil) do Client.rget( "/me/messaging_feature_review", [], {app_id, page_id, :mb_fetch_messaging_feature_review, tx_id} ) end ############################################################################ # Messenger Insights API # ############################################################################ @doc """ Insights API ## Examples iex> metrics = ~w(page_messages_new_conversations_unique page_messages_active_threads_unique) iex> MessengerBot.fetch_insights({"", ""}, {metrics, nil, nil}) {:ok, %{"data" => [%{name: "...", period: "day", values: []}, ]}} """ @spec fetch_insights(page_ref(), {metrics(), integer(), integer()}) :: res() @spec fetch_insights(page_ref(), {metrics(), integer(), integer()}, tx_id()) :: res() def fetch_insights({app_id, page_id}, {metrics, since, until}, tx_id \\ nil) do Client.rget( "/me/insights", [metric: Enum.join(metrics, ","), since: since, until: until], {app_id, page_id, :mb_fetch_insights, tx_id} ) end ############################################################################ # Messenger Profile API # ############################################################################ @doc """ Messenger Profile API / Set account linking url ## Examples iex> url = "https://example.com/fb/auth" iex> MessengerBot.set_account_linking_url({"", ""}, url) {:ok, %{"result" => "success"}} """ @spec set_account_linking_url(page_ref(), String.t()) :: res() @spec set_account_linking_url(page_ref(), String.t(), tx_id()) :: res() def set_account_linking_url({app_id, page_id}, account_linking_url, tx_id \\ nil) do Client.rpost( "/me/messenger_profile", %{account_linking_url: account_linking_url}, {app_id, page_id, :mb_set_messenger_profile, tx_id} ) end @doc """ Messenger Profile API / Reset account linking url ## Examples iex> MessengerBot.reset_account_linking_url({"", ""}) {:ok, %{"result" => "success"}} """ @spec reset_account_linking_url(page_ref()) :: res() @spec reset_account_linking_url(page_ref(), tx_id()) :: res() def reset_account_linking_url({app_id, page_id}, tx_id \\ nil) do Client.rdelete( "/me/messenger_profile", %{fields: ["account_linking_url"]}, {app_id, page_id, :mb_reset_messenger_profile, tx_id} ) end @doc """ Messenger Profile API / Fetch account linking url ## Examples iex> MessengerBot.fetch_account_linking_url({"", ""}) {:ok, %{"data" => [%{"account_linking_url" => "https://..."}]}} """ @spec fetch_account_linking_url(page_ref()) :: res() @spec fetch_account_linking_url(page_ref(), tx_id()) :: res() def fetch_account_linking_url({app_id, page_id}, tx_id \\ nil) do Client.rget( "/me/messenger_profile", [fields: "account_linking_url"], {app_id, page_id, :mb_fetch_messenger_profile, tx_id} ) end @doc """ Messenger Profile API / Set get started ## Examples iex> MessengerBot.set_get_started({"", ""}) {:ok, %{"result" => "success"}} iex> MessengerBot.set_get_started({"", ""}, "JUST_STARTED") {:ok, %{"result" => "success"}} """ @spec set_get_started(page_ref()) :: res() @spec set_get_started(page_ref(), tx_id()) :: res() def set_get_started({app_id, page_id}, payload \\ "GET_STARTED", tx_id \\ nil) do Client.rpost( "/me/messenger_profile", %{get_started: %{payload: payload}}, {app_id, page_id, :mb_set_messenger_profile, tx_id} ) end @doc """ Messenger Profile API / Reset get started ## Examples iex> MessengerBot.reset_get_started({"", ""}) {:ok, %{"result" => "success"}} """ @spec reset_get_started(page_ref()) :: res() @spec reset_get_started(page_ref(), tx_id()) :: res() def reset_get_started({app_id, page_id}, tx_id \\ nil) do Client.rdelete( "/me/messenger_profile", %{fields: ["get_started"]}, {app_id, page_id, :mb_reset_messenger_profile, tx_id} ) end @doc """ Messenger Profile API / Fetch get started ## Examples iex> MessengerBot.fetch_get_started({"", ""}) {:ok, %{"data" => [%{"get_started" => %{"payload" => "..."}}]}} """ @spec fetch_get_started(page_ref()) :: res() @spec fetch_get_started(page_ref(), tx_id()) :: res() def fetch_get_started({app_id, page_id}, tx_id \\ nil) do Client.rget( "/me/messenger_profile", [fields: "get_started"], {app_id, page_id, :mb_fetch_messenger_profile, tx_id} ) end @doc """ Messenger Profile API / Set greeting ## Examples iex> greeting = [%{locale: "default", text: "Hey!"}] iex> MessengerBot.set_greeting({"", ""}, greeting) {:ok, %{"result" => "success"}} """ @spec set_greeting(page_ref(), list(Map.t())) :: res() @spec set_greeting(page_ref(), list(Map.t()), tx_id()) :: res() def set_greeting({app_id, page_id}, greeting, tx_id \\ nil) do Client.rpost( "/me/messenger_profile", %{greeting: greeting}, {app_id, page_id, :mb_set_messenger_profile, tx_id} ) end @doc """ Messenger Profile API / Reset greeting ## Examples iex> MessengerBot.reset_greeting({"", ""}) {:ok, %{"result" => "success"}} """ @spec reset_greeting(page_ref()) :: res() @spec reset_greeting(page_ref(), tx_id()) :: res() def reset_greeting({app_id, page_id}, tx_id \\ nil) do Client.rdelete( "/me/messenger_profile", %{fields: ["greeting"]}, {app_id, page_id, :mb_reset_messenger_profile, tx_id} ) end @doc """ Messenger Profile API / Fetch greeting ## Examples iex> MessengerBot.fetch_greeting({"", ""}) {:ok, %{"data" => [%{"greeting" => [%{}]}]}} """ @spec fetch_greeting(page_ref()) :: res() @spec fetch_greeting(page_ref(), tx_id()) :: res() def fetch_greeting({app_id, page_id}, tx_id \\ nil) do Client.rget( "/me/messenger_profile", [fields: "greeting"], {app_id, page_id, :mb_fetch_messenger_profile, tx_id} ) end @doc """ Messenger Profile API / Set home url ## Examples iex> home_url = %{url: "htt..", webview_height_ratio: "tall"} iex> MessengerBot.set_home_url({"", ""}, home_url) {:ok, %{"result" => "success"}} """ @spec set_home_url(page_ref(), Map.t()) :: res() @spec set_home_url(page_ref(), Map.t(), tx_id()) :: res() def set_home_url({app_id, page_id}, home_url, tx_id \\ nil) do Client.rpost( "/me/messenger_profile", %{home_url: home_url}, {app_id, page_id, :mb_set_messenger_profile, tx_id} ) end @doc """ Messenger Profile API / Reset home url ## Examples iex> MessengerBot.reset_home_url({"", ""}) {:ok, %{"result" => "success"}} """ @spec reset_home_url(page_ref()) :: res() @spec reset_home_url(page_ref(), tx_id()) :: res() def reset_home_url({app_id, page_id}, tx_id \\ nil) do Client.rdelete( "/me/messenger_profile", %{fields: ["home_url"]}, {app_id, page_id, :mb_reset_messenger_profile, tx_id} ) end @doc """ Messenger Profile API / Fetch home url ## Examples iex> MessengerBot.fetch_home_url({"", ""}) {:ok, %{"data" => [%{"home_url" => %{}}]}} """ @spec fetch_home_url(page_ref()) :: res() @spec fetch_home_url(page_ref(), tx_id()) :: res() def fetch_home_url({app_id, page_id}, tx_id \\ nil) do Client.rget( "/me/messenger_profile", [fields: "home_url"], {app_id, page_id, :mb_fetch_messenger_profile, tx_id} ) end @doc """ Messenger Profile API / Set payment_settings """ @spec set_payment_settings(page_ref(), Map.t()) :: res() @spec set_payment_settings(page_ref(), Map.t(), tx_id()) :: res() def set_payment_settings({app_id, page_id}, payment_settings, tx_id \\ nil) do Client.rpost( "/me/messenger_profile", %{payment_settings: payment_settings}, {app_id, page_id, :mb_set_messenger_profile, tx_id} ) end @doc """ Messenger Profile API / Reset payment settings ## Examples iex> MessengerBot.reset_payment_settings({"", ""}) {:ok, %{"result" => "success"}} """ @spec reset_payment_settings(page_ref()) :: res() @spec reset_payment_settings(page_ref(), tx_id()) :: res() def reset_payment_settings({app_id, page_id}, tx_id \\ nil) do Client.rdelete( "/me/messenger_profile", %{fields: ["payment_settings"]}, {app_id, page_id, :mb_reset_messenger_profile, tx_id} ) end @doc """ Messenger Profile API / Fetch payment settings ## Examples iex> MessengerBot.fetch_payment_settings({"", ""}) {:ok, %{"data" => [%{"payment_settings" => %{}}]}} """ @spec fetch_payment_settings(page_ref()) :: res() @spec fetch_payment_settings(page_ref(), tx_id()) :: res() def fetch_payment_settings({app_id, page_id}, tx_id \\ nil) do Client.rget( "/me/messenger_profile", [fields: "payment_settings"], {app_id, page_id, :mb_fetch_messenger_profile, tx_id} ) end @doc """ Messenger Profile API / Set persistent menu ## Examples iex> menu = [] iex> MessengerBot.set_persistent_menu({"", ""}, menu) {:ok, %{"result" => "success"}} """ @spec set_persistent_menu(page_ref(), list()) :: res() @spec set_persistent_menu(page_ref(), list(), tx_id()) :: res() def set_persistent_menu({app_id, page_id}, persistent_menu, tx_id \\ nil) do Client.rpost( "/me/messenger_profile", %{persistent_menu: persistent_menu}, {app_id, page_id, :mb_set_messenger_profile, tx_id} ) end @doc """ Messenger Profile API / Reset persistent menu ## Examples iex> MessengerBot.reset_persistent_menu({"", ""}) {:ok, %{"result" => "success"}} """ @spec reset_persistent_menu(page_ref()) :: res() @spec reset_persistent_menu(page_ref(), tx_id()) :: res() def reset_persistent_menu({app_id, page_id}, tx_id \\ nil) do Client.rdelete( "/me/messenger_profile", %{fields: ["persistent_menu"]}, {app_id, page_id, :mb_reset_messenger_profile, tx_id} ) end @doc """ Messenger Profile API / Fetch persistent menu ## Examples iex> MessengerBot.fetch_persistent_menu({"", ""}) {:ok, %{"data" => [%{"persistent_menu" => [%{}, %{}]}]}} """ @spec fetch_persistent_menu(page_ref()) :: res() @spec fetch_persistent_menu(page_ref(), tx_id()) :: res() def fetch_persistent_menu({app_id, page_id}, tx_id \\ nil) do Client.rget( "/me/messenger_profile", [fields: "persistent_menu"], {app_id, page_id, :mb_fetch_messenger_profile, tx_id} ) end @doc """ Messenger Profile API / Set target audience ## Examples iex> audience = %{audience_type: "custom", countries: %{whitelist: ["US", "TR"]}} iex> MessengerBot.set_target_audience({"", ""}, audience) {:ok, %{"result" => "success"}} """ @spec set_target_audience(page_ref(), Map.t()) :: res() @spec set_target_audience(page_ref(), Map.t(), tx_id()) :: res() def set_target_audience({app_id, page_id}, target_audience, tx_id \\ nil) do Client.rpost( "/me/messenger_profile", %{target_audience: target_audience}, {app_id, page_id, :mb_set_messenger_profile, tx_id} ) end @doc """ Messenger Profile API / Reset target audience ## Examples iex> MessengerBot.reset_target_audience({"", ""}) {:ok, %{"result" => "success"}} """ @spec reset_target_audience(page_ref()) :: res() @spec reset_target_audience(page_ref(), tx_id()) :: res() def reset_target_audience({app_id, page_id}, tx_id \\ nil) do Client.rdelete( "/me/messenger_profile", %{fields: ["target_audience"]}, {app_id, page_id, :mb_reset_messenger_profile, tx_id} ) end @doc """ Messenger Profile API / Fetch target audience ## Examples iex> MessengerBot.fetch_target_audience({"", ""}) {:ok, %{"data" => [%{"target_audience" => %{}}]}} """ @spec fetch_target_audience(page_ref()) :: res() @spec fetch_target_audience(page_ref(), tx_id()) :: res() def fetch_target_audience({app_id, page_id}, tx_id \\ nil) do Client.rget( "/me/messenger_profile", [fields: "target_audience"], {app_id, page_id, :mb_fetch_messenger_profile, tx_id} ) end @doc """ Messenger Profile API / Set whitelisted domains ## Examples iex> domains = ["https://bit.ly/", "https://github.com"] iex> MessengerBot.set_whitelisted_domains({"", ""}, domains) {:ok, %{"result" => "success"}} """ @spec set_whitelisted_domains(page_ref(), list(String.t())) :: res() @spec set_whitelisted_domains(page_ref(), list(String.t()), tx_id()) :: res() def set_whitelisted_domains({app_id, page_id}, whitelisted_domains, tx_id \\ nil) do Client.rpost( "/me/messenger_profile", %{whitelisted_domains: whitelisted_domains}, {app_id, page_id, :mb_set_messenger_profile, tx_id} ) end @doc """ Messenger Profile API / Reset whitelisted domains ## Examples iex> MessengerBot.reset_whitelisted_domains({"", ""}) {:ok, %{"result" => "success"}} """ @spec reset_whitelisted_domains(page_ref()) :: res() @spec reset_whitelisted_domains(page_ref(), tx_id()) :: res() def reset_whitelisted_domains({app_id, page_id}, tx_id \\ nil) do Client.rdelete( "/me/messenger_profile", %{fields: ["whitelisted_domains"]}, {app_id, page_id, :mb_reset_messenger_profile, tx_id} ) end @doc """ Messenger Profile API / Fetch whitelisted domains ## Examples iex> MessengerBot.fetch_whitelisted_domains({"", ""}) {:ok, %{"data" => [%{"whitelisted_domains" => ["https://bit.ly/", ]}]}} """ @spec fetch_whitelisted_domains(page_ref()) :: res() @spec fetch_whitelisted_domains(page_ref(), tx_id()) :: res() def fetch_whitelisted_domains({app_id, page_id}, tx_id \\ nil) do Client.rget( "/me/messenger_profile", [fields: "whitelisted_domains"], {app_id, page_id, :mb_fetch_messenger_profile, tx_id} ) end ############################################################################ # Send API # ############################################################################ @doc """ Send API Please refer to platform documentation for message types and payloads: https://developers.facebook.com/docs/messenger-platform/reference/send-api/ ## Examples iex> req = %{messaging_type: "...", recipient: %{id: "12"}, message: %{text: "hi!"}} iex> MessengerBot.send_message({"", ""}, req) {:ok, %{recipient_id" => "12", "message_id" => "mid..."}} """ @spec send_message(page_ref(), Map.t()) :: res() @spec send_message(page_ref(), Map.t(), tx_id()) :: res() def send_message({app_id, page_id}, %{} = req, tx_id \\ nil) do Client.rpost( "/me/messages", req, {app_id, page_id, :mb_send_message, tx_id} ) end ############################################################################ # Unlink Account API # ############################################################################ @doc """ Account Linking API / unlink_accounts ## Examples iex> req = %{psid: "PSID"} iex> MessengerBot.unlink_account({"", ""}, req) {:ok, %{"result" => "unlink account success"}} """ @spec unlink_account(page_ref(), Map.t()) :: res() @spec unlink_account(page_ref(), Map.t(), tx_id()) :: res() def unlink_account({app_id, page_id}, %{} = req, tx_id \\ nil) do Client.rpost( "/me/unlink_accounts", req, {app_id, page_id, :mb_unlink_account, tx_id} ) end ############################################################################ # User Profile API # ############################################################################ @doc """ User Profile API / user_profiles ## Examples iex> user_id = 1234567890 iex> fields = ~w(first_name last_name profile_pic locale timezone gender) iex> MessengerBot.fetch_user_profile({"", ""}, {user_id, fields}) {:ok, %{"first_name" => "...", "last_name" => "...", }} """ @spec fetch_user_profile(page_ref(), {user_id(), user_profile_fields()}) :: res() @spec fetch_user_profile(page_ref(), {user_id(), user_profile_fields()}, tx_id()) :: res() def fetch_user_profile({app_id, page_id}, {user_id, fields}, tx_id \\ nil) do Client.rget( "/#{user_id}", [fields: Enum.join(fields, ",")], {app_id, page_id, :mb_fetch_user_profile, tx_id} ) end ############################################################################ # PRIVATE # ############################################################################ defp app_secret_proof({app_id, page_id}) do page_token = Config.page_token(app_id, page_id) app_secret = Config.app_secret(app_id) Encryption.calculate_sha256(app_secret, page_token) end defp app_secret_proof({app_id}) do app_access_token = Config.app_access_token(app_id) app_secret = Config.app_secret(app_id) Encryption.calculate_sha256(app_secret, app_access_token) end end