This post was generated by an AI agent from an article the account owner published in Japanese on note. The wording is not human-written.
A PHP-based bridge between LINE WORKS and Chatwork was built to solve a workflow annoyance: some clients prefer contacting through LINE WORKS, while all project management happens in Chatwork. Bouncing between two tools, forgetting which client uses which platform, scattered file storage, and having to search two separate histories were the pain points that motivated the project. The idea was simple: auto-forward LINE WORKS messages into Chatwork so only Chatwork needed to be checked.
The system
The bridge was built on a rental server (heteml) using plain PHP with no external libraries, relying only on OpenSSL and curl.
chatwork2lineworks/
├── config.php # configuration
├── callback.php # LINE WORKS → Chatwork (Webhook)
├── cron_chatwork.php # Chatwork → LINE WORKS (CRON)
├── lineworks_api.php # LINE WORKS API
├── chatwork_api.php # Chatwork API
├── logger.php # logging
└── .htaccess # security settings
LINE WORKS → Chatwork ran in real time: the LINE WORKS bot receives a message, a webhook notifies the server, and the message is forwarded to Chatwork. Chatwork → LINE WORKS ran on polling: a CRON job periodically fetches new Chatwork messages and sends them out via the LINE WORKS bot. Both text and file/image transfers were supported.
It worked — internally
Testing between an internal LINE WORKS account and Chatwork succeeded in both directions: sending a message to the LINE WORKS bot showed up in Chatwork, and writing in Chatwork arrived via the LINE WORKS bot. Technically, it worked.
Then came the external client test
When testing the actual use case — forwarding conversations with external clients — several platform restrictions showed up one after another.
External users can't reach a bot at all. LINE WORKS bots are only accessible to members of the same organization. A LINE WORKS user from another company (an external contact) cannot message a bot created by a different organization, and in fact cannot even see it.
Bots can't be added to groups containing external users. Putting the bot into a group chat looked like a workaround, but the option to add a bot simply doesn't appear in any group that includes external users. The same restriction applies when creating a new group: selecting an external user disables the bot tab.
There's no API to monitor a user's own chats. Without going through a bot, reading personal chat history directly via the API also isn't possible — the LINE WORKS API has no feature for reading messages between users. The Bot API only exposes messages sent directly to the bot.
The breakdown:
| Scenario | Possible? | Why |
|---|---|---|
| Forwarding bot ↔ internal member messages | Yes | Within Bot API scope |
| Forwarding internal-only group messages | Yes | Bots can be added to internal groups |
| Forwarding exchanges with external clients | No | Bot is inaccessible to them |
| Auto-forwarding one's own chat history | No | No such API exists |
The original goal — automatically forwarding LINE WORKS conversations with external clients into Chatwork — turned out to be impossible with the LINE WORKS Bot API.
Technical snags along the way
A few implementation details are worth recording for anyone attempting something similar.
JWT authentication (RS256). LINE WORKS API authentication requires a JWT signed with RS256. It can be implemented with openssl_sign() without libraries like firebase/php-jwt. Forgetting Base64URL encoding (converting +/ to -_ and stripping trailing =) causes authentication errors. If a private key file path is correct but still unreadable, check line endings and BOM.
Chatwork API's differential fetching. GET /rooms/{roomId}/messages never returns a message that has already been retrieved once. Calling the API effectively marks messages as read, so a processing failure means that message can't be fetched again. The force=1 parameter forces a fetch but only returns the latest 100 messages.
Scope mismatches. The scope parameter requested when obtaining a LINE WORKS access token must match what's enabled in the Developer Console. The bot scope alone returns a 403 on the user info API (/users/{userId}); displaying usernames requires the directory.read scope. Token caches need to be cleared after changing scopes.
A PHP comment landmine. Writing a CRON example like */3 * * * * inside a PHP doc comment causes a parse error, because */ is interpreted as the comment's closing delimiter — easy to miss on first encounter.
Alternatives
For the same goal, two alternatives exist. Using a LINE Official Account (ordinary LINE, not LINE WORKS) instead allows a similar system to be built, since anyone can add a LINE Official Account as a friend with no external-user restriction, the Messaging API supports webhooks just like LINE WORKS, and a free plan exists (up to 200 outgoing messages per month, unlimited incoming). If a client specifically wants to use LINE, this is the correct tool. The simpler alternative is standardizing everyone onto Chatwork.
What the LINE WORKS Bot API is still good for
Even though it didn't fit this use case, the LINE WORKS Bot API is capable for internal use: internal chatbots for inquiries and FAQs, operational notifications like server monitoring alerts or daily report reminders, attendance tracking (sending "clock in" to a bot to record it in an attendance system), approval flows (requesting approval via bot, completing it with "OK"), internal system integration such as inventory or customer lookups, and scheduled group notifications. The key constraint is that it's limited to internal use — anyone considering integration with external users should look at the LINE Messaging API instead.
| Use case | LINE WORKS Bot API | LINE Messaging API |
|---|---|---|
| Internal process automation | Best fit | Not suited |
| Internal chat + other service integration | Best fit | Not suited |
| External client integration | Not possible | Best fit |
| Unified customer-facing support | Not possible | Best fit |
Takeaways
The LINE WORKS Bot API is scoped strictly to internal use and cannot forward messages exchanged with external clients. For the same forwarding goal, the LINE Messaging API should be the first thing evaluated. The implementation itself wasn't the hard part — PHP, curl, and OpenSSL were enough to build a working bridge. The question to settle before writing any code is simply: is the other side of the conversation internal or external? Answering that first avoids discovering the limitation only after the system is built.
Follow @kmrb_works here on DEV for more field notes from real development work. Also on X and note, mostly in Japanese.
Top comments (0)