目次
Connector

HubSpot

HubSpot Connectorは、HubSpotのアカウントからCRMのオブジェクト、その関連、エンゲージメントを読み、レコードを書き戻し、レコード同士を関連付け、ワークフローに登録します。会社や取引を外部のデータでスコアリングする、CRMのプロパティを最新に保つ、レコードをHubSpot自身の自動化に渡す、といった用途に使います。

読み取り元

標準のCRMオブジェクトとカスタムオブジェクトが読み取り元です。hubspot.companies、hubspot.contacts、hubspot.deals、hubspot.tickets、カスタムオブジェクトはその名前で参照します。列はオブジェクトのプロパティで、アカウントのスキーマから検出されるので、HubSpot側でプロパティを足せば、Connectorを変えなくても列として使えます。すべてのオブジェクトのキーは id です。

  • hubspot.associations — 2つのレコードの関連ごとに1レコード。from_object、from_id、to_object、to_id、type。取引の会社やチケットのコンタクトはここのレコードなので、HubSpotのオブジェクト同士のJOINは、これを通した普通の JOIN です。よくある用途のために、各オブジェクトは主な関連をidの列(取引の company_id など)としても持ちます。
  • hubspot.engagements — メモ、通話、メール、ミーティング、タスク。id、type、timestamp、owner_id、body、そして関連付けられたレコードのid。

型

HubSpotのプロパティ型ActQL備考
stringstring
numberdecimal(38, 10)HubSpotの数値は任意精度のdecimal。通貨のプロパティはアカウントの精度を保つ
boolbool
enumeration(select、radio)stringラベルではなく内部の値。選択肢にない値の書き込みは、その項目を失敗させる
enumeration(checkbox、複数)string の arrayConnectorが ; で分割・結合する
datedate
datetimetimestampミリ秒精度のUTCの時点
object_coordinates、phone_numberstring
関連のidstringHubSpotのAPIと同じく、レコードのidは文字列
計算、ロールアップ、スコアのプロパティその結果の型読み取りのみ。書き込みは check で失敗する

書き込みは同じ規則で逆方向に変換します。プロパティに収まらない値は、静的に分かるなら check で、そうでなければその項目が失敗します。

Effectと操作

レコードのEffectはキーで書きます。

  • insert — EFFECT INSERT hubspot.companies (name, domain, …) VALUES (…)。
  • update — EFFECT UPDATE hubspot.companies ID id SET (…)。
  • upsert — EFFECT UPSERT hubspot.contacts ID email SET (…)。キーは、HubSpotが一意として扱うプロパティ(コンタクトの email、会社の domain、一意とマークしたカスタムプロパティ)です。HubSpotはそれを idProperty として照合し、一致するものがなければレコードを作成します。
  • delete — EFFECT DELETE hubspot.companies ID id(HubSpotはレコードをアーカイブします。ごみ箱から復元できます)。

ID で指定するキーは、ちょうど1レコードを識別しなければなりません。id は常にそうです。一意なプロパティはHubSpot自身の強制によって一意で、一意とマークされていないプロパティはConnectorが check で拒否します。同じキーに対して元のレコードが2つの異なる値を持つ更新は、check で拒否されます。

操作:

  • associate — EFFECT COMMAND hubspot.associate TARGET deal_id ID key INPUT (to_object = 'companies', to_id = company_id, type = 'deal_to_company') は、2つのレコードをラベル付きの関連で結び付けます。
  • enroll — EFFECT COMMAND hubspot.enroll TARGET contact_id ID key INPUT (workflow = @workflow_id) は、コンタクトをワークフローに登録します。

セットアップ

"hubspot": {
  "connector": "hubspot",
  "credentials": {"access_token": {"env": "HUBSPOT_ACCESS_TOKEN"}}
}

プライベートアプリのトークンを使います。アプリには、プログラムが読むオブジェクトごとに crm.objects.<object>.read、書くオブジェクトごとに crm.objects.<object>.write のスコープ(たとえば crm.objects.companies.read と crm.objects.companies.write)、プロパティの検出に crm.schemas.<object>.read、ワークフロー登録に automation が必要です。関連には両側のオブジェクトのスコープを使います。

ActQL Cloudでは、HubSpotはCloudのホスト型OAuthアプリケーションを通して接続します。プライベートアプリのトークンもそのまま使えます。

Capabilityとプッシュダウン

演算プッシュダウンされる条件
列の選択常に。参照されるプロパティだけを要求する
WHERE述語が1つのオブジェクトのプロパティと、検索APIがActQLと同じ意味で評価する演算子だけを使うとき。=、!=、<、>、IN、IS NULL、末尾に % を置いた LIKE(前方一致)。全文検索の CONTAINS_TOKEN は LIKE には使わない。複数のオブジェクトや読み取り元にまたがる述語はエンジンに残すか分割し、残りはHostが評価する
ORDER BY、LIMIT並べ替えが1つのプロパティに対するもので、件数が検索APIの10,000件の範囲内のとき。それを超える場合、Connectorはリストのエンドポイントで読み、Hostで並べ替える
集計HubSpotの中では行わない。取得したレコードに対してHostで集計する
JOINHubSpotの中では行わない。関連のidの列か hubspot.associations を通して、エンジンで実行する

explain は、プッシュダウンされたステップをSite connector:hubspot、Interface HubSpot API で表示します。

プレビューと突き合わせ

プレビュー。 更新、UPSERT、削除は full_diff でプレビューします。Connectorは対象のレコードをキーで読み、現在のプロパティの値と各レコードの hs_lastmodifieddate を記録し、プレビューにはプロパティごとに現在の値と新しい値が出ます。HubSpotには条件付きの書き込みがないので、適用時にConnectorは同じバッチ呼び出しの中で各対象を読み直し、プレビューしたプロパティが変わっていないときだけ更新を送ります。その間に変わったレコードは更新されません。その項目は failed(conflict)で終わり、続けるよう求められればRunは新しいプレビューを作ります。追加は targeted でプレビューし、すべてのプロパティの値を示します。関連付けは両方のレコードと種類を、ワークフロー登録はコンタクトとワークフローをプレビューします。

突き合わせ。 すべての書き込みは、Connectorが生成してEffectの項目に対して記録したリクエストIDのもとで、バッチのエンドポイントを通して送ります。書き込んだ各レコードは、接続で指定したプロパティ(オブジェクトに一度だけ作る actql_request_id)にそのリクエストIDを持ちます。応答が失われたら、対象のレコードのプロパティ履歴を読んで突き合わせます。HubSpotは各変更をその出所(この連携のアプリid)と時刻とともに記録するので、Connectorは、リクエストの時間帯にこのアプリが行い、リクエストIDのプロパティを設定した変更を探します。値が一致していることや、hs_lastmodifieddate が新しいことだけでは証跡になりません。作成はリクエストIDのプロパティを検索して、関連付けは同じリクエストでこのアプリが書いたプロパティ履歴の記録で(HubSpotは関連付け自体にリクエストIDを保存しないので、記録がなければ unknown のまま)、ワークフロー登録はそのコンタクトのワークフローの登録履歴を読んで突き合わせます。これらで結果が確定しなければ、項目は unknown のままで、何も再送しません。操作は、HubSpotが要求を受け付ければ accepted、関連付けや登録が見えるようになれば applied、どちらも確定できなければ unknown で終わります。

上限と費用

  • HubSpotはアカウントごとに、10秒あたりと1日あたりのリクエスト数を制限しています。Connectorはその範囲内で読み書きのペースを調整し、1日の上限を超えそうなプログラムは送信前に失敗させます。
  • 読み取りは1回に100レコード(リストのエンドポイントでは200)ずつページングされ、検索APIは1つのクエリにつき最大10,000件を返します。Connectorはプログラムの件数の上限までページをたどり、途中までの結果を返すのではなくエラーで止まります。
  • 検索結果は結果整合です。数秒前に変わったレコードが、まだ絞り込みに一致しないことがあります。idでの読み取りは常に最新で、プレビューはidでの読み取りから作ります。
  • バッチの書き込みは1回の呼び出しで最大100レコードです。それより大きいEffectは複数の呼び出しに分けて送り、それぞれが自分のリクエストIDを持ちます。

例

90日より長く開いたままの取引です。

FROM hubspot.deals
|> WHERE stage NOT IN ('closedwon', 'closedlost')
     AND createdate < TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 90 DAY)
|> SELECT id, dealname, amount, createdate
|> ORDER BY amount DESC;

会社にスコアを付けて書き戻します。

SELECT c.id AS id, c.description AS notes, u.active_users, u.trend
FROM hubspot.companies AS c
JOIN snowflake.usage_30d AS u ON c.id = u.account_id
|> INFER `model-task:churn-risk.v1`
     INPUT (notes, active_users, trend) AS risk
|> WHERE risk.outcome = 'ok' AND risk.value.level = 'high'
|> EFFECT UPDATE hubspot.companies
     ID id SET (churn_risk = risk.value.level, risk_reason = risk.value.reason);

その会社のコンタクトを、解約防止のワークフローに登録します。

FROM hubspot.companies AS c
|> WHERE c.churn_risk = 'high'
|> JOIN hubspot.associations AS a
     ON a.from_object = 'companies' AND a.from_id = c.id AND a.to_object = 'contacts'
|> SELECT a.to_id AS contact_id
|> EFFECT COMMAND hubspot.enroll TARGET contact_id ID contact_id
     INPUT (workflow = @retention_workflow);

Source: actql/actql/docs/connectors/hubspot.md at d904416674e4 · Edit on GitHub