Salesforceのホームからfreeeに打刻する
freee人事労務のAPIを画面フローから呼ぶと、Salesforceのホームで出勤と退勤を打刻できます。2021年に作った自社の仕組みを、2026年9月時点のAPIの仕様とSalesforceの公式ヘルプで確かめ直し、Apexのサンプルを足しました。
どういうときに使うのか
私たちはfreee人事労務で勤怠を管理しています。freee人事労務にはWeb画面やアプリから打刻する機能がありますが、打刻のためだけに別の画面を開くのは手間です。
私たちの会社ではSalesforceが業務の中心で、仕事を始めるときに必ず開きます。そこで、Salesforceのホーム画面から、そのまま出勤と退勤を打刻できるようにしました。
作ったものは次の4つです。
| 部品 | 役目 |
|---|---|
| freeeのアプリ | SalesforceからfreeeのAPIを呼ぶための Client ID と Client Secret を発行する |
| 認証プロバイダと指定ログイン情報 | OAuthでfreeeに認証し、APIの呼び出し先をまとめる |
| Apexのクラス | 打刻できる種別を取る処理と、打刻する処理を画面フローから呼べるようにする |
| 画面フロー | ホームに置き、「出勤」か「退勤」を表示して打刻する |
freee側でアプリを作る
アプリを作る
freeeのアプリストアの開発者向け画面でアプリを作ります。発行された Client ID と Client Secret は、あとでSalesforceの認証プロバイダに入れます。
コールバックURLはあとで上書きする
コールバックURLは、Salesforceで認証プロバイダを作ったあとに表示されるURLへ書き換えます。
権限を付ける
権限設定で、打刻の参照と登録ができるようにします。
Salesforce側の設定
リモートサイトの設定
当時は、freeeの認証のURLと、APIのURLの2つをリモートサイトに登録していました。
認証プロバイダ
種類は Open ID Connect にし、freeeのアプリの Client ID と Client Secret を入れます。承認とトークンのエンドポイントには、freeeの認証のURLを入れます。
承認エンドポイントの https://accounts.secure.freee.co.jp/public_api/authorize は、2026年9月時点のfreeeのクイックスタートでも同じURLです。
指定ログイン情報
URLに https://api.freee.co.jp/hr/api/v1 を入れ、ID種別をユーザ、認証プロトコルをOAuth 2.0、認証プロバイダを上で作ったものにします。ID種別をユーザにすると、打刻は利用者それぞれのfreeeアカウントで行われます。
Apexで2つの処理を作る
freee人事労務のAPIで使うのは、次の3つです。2026年9月時点のfreee公式のAPIスキーマで確かめました。
| API | 使いどころ |
|---|---|
GET /api/v1/users/me | ログインユーザーの事業所IDと従業員IDを取る |
GET /api/v1/employees/{employee_id}/time_clocks/available_types | いま打刻できる種別を取る。すでに出勤していれば、休憩開始と退勤が返る |
POST /api/v1/employees/{employee_id}/time_clocks | 打刻する。事業所IDと種別(clock_in、break_begin、break_end、clock_out)が必須 |
当時は自社用に書いたコードで、エラー処理が不十分だったため掲載していませんでした。今回、同じ考え方のサンプルを書き直しました。
public with sharing class FreeeHrApi { public class FreeeHrException extends Exception {} public class Me { public Integer companyId; public Integer employeeId; } // ログインユーザーが従業員として登録されている事業所を1つ返す public static Me me() { Map<String, Object> body = send('GET', '/users/me', null); for (Object c : (List<Object>) body.get('companies')) { Map<String, Object> company = (Map<String, Object>) c; if (company.get('employee_id') != null) { Me m = new Me(); m.companyId = (Integer) company.get('id'); m.employeeId = (Integer) company.get('employee_id'); return m; } } throw new FreeeHrException('freee人事労務に従業員として登録されていません'); } public static Map<String, Object> send(String method, String path, Map<String, Object> payload) { HttpRequest req = new HttpRequest(); req.setEndpoint('callout:FreeeHrUser' + path); req.setMethod(method); req.setTimeout(20000); if (payload != null) { req.setHeader('Content-Type', 'application/json'); req.setBody(JSON.serialize(payload)); } HttpResponse res = new Http().send(req); if (res.getStatusCode() >= 300) { throw new FreeeHrException('freee APIの呼び出しに失敗しました: ' + res.getStatusCode() + ' ' + res.getBody()); } return (Map<String, Object>) JSON.deserializeUntyped(res.getBody()); } }
指定ログイン情報を通してfreee人事労務のAPIを呼ぶ共通処理
public with sharing class FreeeHrGetTimeClocksAvailableType { @InvocableMethod(label='freee 打刻可能種別の取得') public static List<String> run() { FreeeHrApi.Me m = FreeeHrApi.me(); Map<String, Object> body = FreeeHrApi.send('GET', '/employees/' + m.employeeId + '/time_clocks/available_types?company_id=' + m.companyId, null); List<Object> types = (List<Object>) body.get('available_types'); String result = ''; if (types.contains('clock_in')) { result = 'clock_in'; } else if (types.contains('clock_out')) { result = 'clock_out'; } return new List<String>{ result }; } }
いま打刻できる種別を出勤か退勤で返す
public with sharing class FreeeHrPostTimeClocks { @InvocableMethod(label='freee 打刻の登録') public static List<String> run(List<String> types) { FreeeHrApi.Me m = FreeeHrApi.me(); FreeeHrApi.send('POST', '/employees/' + m.employeeId + '/time_clocks', new Map<String, Object>{ 'company_id' => m.companyId, 'type' => types[0] }); return new List<String>{ types[0] }; } }
画面フローから受け取った種別で打刻する
画面フローとホームへの配置
画面は、コードを書かずに画面フローで作りました。最初の画面で「次へ」を押すと打刻できる種別を取り、2つ目の画面で「出勤」か「退勤」を出し、もう一度「次へ」で打刻します。
動かしてみる
利用者がfreeeの認証を通す
個人設定の「外部システムの認証設定」で、指定ログイン情報「FreeeHrUser」を選び、保存時に認証フローを開始します。freeeの画面で「許可する」を押すと、Salesforceに戻って認証が終わります。
ホームで「次へ」を押す
ここでAPIを呼び、いま打刻できる種別を取ります。
「出勤」か「退勤」を確かめて打刻する
見間違いを防ぐため、出勤はオレンジ、退勤は青で表示しました。もう一度「次へ」を押すと、freee人事労務に打刻されます。
確認した環境
- 2026年9月時点のfreee公式のAPIスキーマ(freee-api-schema の人事労務API)、freeeのクイックスタート、Salesforce公式ヘルプ「Understand Legacy Named Credentials」で確認しています
- 当時の仕組みは、2021年3月にSandboxで動かしています
- 画像は2021年当時のものです。右上のユーザーアイコン、コールバックURL、Client ID、認証プロバイダID、コンシューマ鍵、作成者と更新者の名前を白で伏せています
まとめ
- freee人事労務のAPIを画面フローから呼ぶと、Salesforceのホームで打刻できます
- 使うAPIは、ログインユーザーの取得、打刻可能種別の取得、打刻の登録の3つです
- 指定ログイン情報のID種別をユーザにすると、利用者それぞれのfreeeアカウントで打刻されます
- 当時の形式の指定ログイン情報は非推奨です。いま作るなら新しい形式で作ります
- 打刻できる種別を先に取り、その結果だけを画面に出すと、不整合な打刻を防げます
Salesforceの導入・運用についてご相談ください
導入前の検討から、お使いの環境の改修・運用、AIとの連携まで承ります。状況を伺ったうえで、進め方をご提案します。