MoneyForward Cloud Integration #
MoneyForward Cloud is a suite of Japanese cloud accounting products. BonsAI integrates with Cloud Accounting (クラウド会計) and Cloud Invoice (クラウド請求書) for master data synchronization and AR invoice reads.
Architecture Overview #
MoneyForward is not a single-app integration like Xero or QBO. Each MF Cloud product is a separate service, but Cloud Accounting and Cloud Invoice share a unified OAuth auth server at https://api.biz.moneyforward.com. This lets a single OAuth app request scopes from both products in one authorization flow.
User → BonsAI OAuth authorize → MF App Portal consent
↓
auth code callback
↓
BonsAI exchanges for tokens
↓
┌─────────────────────────────────────────────┐
│ Cloud Accounting API (master data) │
│ https://api-accounting.moneyforward.com │
├─────────────────────────────────────────────┤
│ Cloud Invoice API (AR invoices) │
│ https://invoice.moneyforward.com │
└─────────────────────────────────────────────┘
Products & Scopes #
Cloud Accounting (クラウド会計) #
Provides COA master data: accounts, taxes, departments, trade partners, journal entries.
| Scope | Access |
|---|---|
mfc/accounting/offices.read |
Office/company info |
mfc/accounting/accounts.read |
Chart of accounts |
mfc/accounting/departments.read |
Departments |
mfc/accounting/taxes.read |
Tax rates/codes |
mfc/accounting/trade_partners.read |
Trade partners (contacts) |
mfc/accounting/trade_partners.write |
Create/update trade partners |
mfc/accounting/journal.read |
Journal entries |
mfc/accounting/journal.write |
Create/update/delete journal entries (publish) |
mfc/accounting/voucher.write |
Upload/unlink 証憑 voucher files (publish attachments) |
Scope migration:
journal.writeandvoucher.writewere added for publish. The App Portal app registration must include them, and existing connections must re-authorize before publish works (API calls under the old consent return 403 for the new scopes).
Cloud Invoice (クラウド請求書) #
Provides AR invoice data: billings, partners, items, quotes.
| Scope | Access |
|---|---|
mfc/invoice/data.read |
All Invoice API objects (read-only) |
Multiple scopes are space-delimited in the authorize URL:
scope=mfc/accounting/offices.read mfc/accounting/accounts.read mfc/invoice/data.read
Auth Endpoints #
All endpoints below are for the unified auth server shared by Cloud Accounting and Cloud Invoice.
| Endpoint | URL |
|---|---|
| Authorization | https://api.biz.moneyforward.com/authorize |
| Token | https://api.biz.moneyforward.com/token |
| Revoke | https://api.biz.moneyforward.com/revoke |
Client authentication method: CLIENT_SECRET_BASIC (HTTP Basic Auth with client_id:client_secret in the Authorization header).
Token Lifetimes #
| Token | Lifetime | Notes |
|---|---|---|
| Access token | 1 hour (3600s) | |
| Refresh token | 18 months (~540 days / 46,656,000s) | Expiry resets on each use |
| Auth code | 10 minutes |
Refresh token rotation: Each refresh issues a new access + refresh token pair. The old tokens are invalidated immediately. The token store must persist both the new access_token and the new refresh_token from every refresh response.
API Base URLs #
| Product | API Base |
|---|---|
| Cloud Accounting | https://api-accounting.moneyforward.com/api/v3/ |
| Cloud Invoice | https://invoice.moneyforward.com/api/v3/ |
OAuth App Registration #
App Portal URL #
https://biz.moneyforward.com/app_portal
Navigate from the MF Cloud management console → sidebar → App Portal.
Pre-requisites #
Before registering an OAuth app, the MoneyForward Cloud account must have:
- An active MF Cloud subscription with Cloud Accounting and/or Cloud Invoice enabled (any plan tier).
- A user with 全権管理者 (superadmin) permission to activate the App Portal for the first time.
- A user with アプリ開発 (App Development) permission to register the app and obtain credentials.
- For production: a separate user with アプリ連携 (App Integration) permission to authorize the OAuth consent screen (MF best practice: keep dev and auth roles separate in production).
Registration Steps #
-
Log into MoneyForward Cloud management console.
-
Open App Portal from the left sidebar.
-
Click 「アプリを作成」 (Create App).
-
Fill in the registration form:
Field Value App name BonsAI (Cloud Accounting + Invoice) [env]Redirect URI https://[bonsapi-host]/api/v1/integrations/oauth/authorize/callbackClient auth method CLIENT_SECRET_BASICScopes Select all required scopes listed above -
After creation, copy the Client ID and Client Secret.
-
Store credentials in Doppler (see Credential Storage).
Per-Environment Configuration #
Register one app per environment:
| Environment | App Name Suffix | Redirect URI Host |
|---|---|---|
| dev_local | [dev] |
http://localhost:8080 |
| dev_aws | [dev] |
Dev environment bonsapi host |
| prod | [prod] |
Production bonsapi host |
Full callback URL pattern:
{bonsapi-host}/api/v1/integrations/oauth/authorize/callback
Credential Storage #
Doppler Keys #
All MoneyForward credentials are stored in Doppler under project bonsai:
| Doppler Key | Description |
|---|---|
MONEY_FORWARD_CLIENT_ID |
OAuth Client ID |
MONEY_FORWARD_CLIENT_SECRET |
OAuth Client Secret |
These are set per Doppler config (dev_local, dev_aws, prod).
Local Development #
For local development, credentials can be configured in .config.yaml:
moneyforward:
client_id: ""
client_secret: ""
These are mapped to environment variables by override-coder-env.sh.
Credential Rotation #
-
Create new credentials in the MF App Portal:
- Open App Portal → select the app → regenerate client secret.
- The old secret remains valid until you explicitly revoke it (if MF supports dual secrets), or is immediately invalidated (check portal behavior).
-
Update Doppler:
doppler secrets set MONEY_FORWARD_CLIENT_SECRET="new-secret" \ --project bonsai --config <env> -
Restart services to pick up new secrets:
kubectl rollout restart deployment/bonsapi-deployment -
Verify the integration still works by triggering a token refresh.
-
Document the rotation in the change log.
Revoking a Connection #
To revoke a user’s OAuth connection:
-
Via API — POST to the revoke endpoint:
POST https://api.biz.moneyforward.com/revoke Content-Type: application/x-www-form-urlencoded Authorization: Basic base64(client_id:client_secret) token={refresh_token} -
Via MF Portal — The connected user can disconnect the app from their MF Cloud settings → 連携アプリ管理 (Connected App Management).
-
Verify revocation — After revoking, confirm a
401 Unauthorizedresponse when using the old access token:curl -H "Authorization: Bearer {old_access_token}" \ https://api-accounting.moneyforward.com/api/v3/offices # Expected: 401 Unauthorized
Publish (AP bills / AR invoices / Direct expenses) #
MoneyForward Cloud Accounting has no document-level object — publish creates a journal (仕訳)
via POST /api/v3/journals, with one main-side row per line and the contra side consolidated
per account (the layout BonsAI’s Journal Entry Review shows — e.g. three expense debits against
a single 小口現金 credit carrying the summed value). Branches may carry only one side
(CRUDJournalLine requires neither debitor nor creditor); the journal balances as a whole and
reads back through our own journal-classification rules:
| Document | Debit (借方) | Credit (貸方) |
|---|---|---|
| AP bill | expense line account, per line | 買掛金 (or per-line credit override in double-entry mode), consolidated per account |
| AR invoice | 売掛金 (or per-line debit override), consolidated per account | revenue line account, per line |
| Direct expense | expense line account, per line | header paid-from account (or per-line credit override), consolidated per account |
Consolidated contra rows keep the tax rate / department only when uniform across the merged lines (mixed values are dropped rather than guessed), matching the Journal Entry Review.
Key behaviors:
- Republish is delete + re-create (
DELETE /api/v3/journals/{id}thenPOST /api/v3/journals), the sameshould_delete_before_publishflow as Sage/freee;update_invoice/update_direct_expenseare intentionallyUnimplemented. The journal id and 仕訳番号 change on republish, soexternal_idis re-persisted and 証憑 are re-uploaded from the extraction pages. Unpublish isDELETE. - Amounts are tax-inclusive integer yen. The write schema has no
tax_value— MoneyForward derives tax fromvalue+tax_id, so it is the source of truth for tax after publish. - Attachments are 証憑 vouchers (
POST /api/v3/vouchers, Base64): max 5 MB per file, max 5 per journal.DELETE /api/v3/vouchersonly unlinks (電帳法 — the file survives in the クラウドBox trash). Download is not possible (Cloud Box has no GA download API). - Detail fetch is lenient.
fetch_invoice/fetch_direct_expensefirst try the strict AR/AP/expense shape; when a journal we published does not match (user-chosen debit/credit account in double-entry mode, non-REVENUE/EXPENSE line account) they log a warning and fall back to a shape-agnostic read (all non-contra lines, journal total) instead ofNotFound. Only the list endpoints keep the strict filter. This matters because the post-publish attachment sync re-reads the journal throughfetch_invoice; aNotFoundthere failed the publish and retried forever. - Single-entry mode resolves the contra account to the office’s sole 買掛金/売掛金 account and errors if none or several exist; double-entry mode uses the per-line debit/credit selections.
- 取引先 are addressed by trade partner code (our contact ids already are codes).
- 部門 (departments) map from the line’s first tag; more than one tag per line is rejected.
- インボイス区分 is sent as
INVOICE_KIND_QUALIFIEDonly when the document carries a valid 適格請求書発行事業者番号 (T-number); otherwise it is omitted so MF applies its default. - Journals have no payment status, so published documents are always
Authorized; the paid-invoice delete guard in accounting-sync never triggers for MoneyForward. - Auto-publish defaults are switched off on first connect (same policy as Sage/freee).
- Bank statement publish is not yet implemented (candidate follow-up: journals per transaction,
or the 明細
POST /api/v3/transactions+journalizebank-feed route, scopetransaction.write).
Verify against a real office (no sandbox exists): tax derivation vs user-edited tax amounts under
税込/税抜 term settings, sub_account_id+parent pairing, and voucher re-upload across republish.
Important Constraints #
No Sandbox Environment #
MoneyForward Cloud does not provide a sandbox or test environment. All dev/staging testing requires a real paid MF Cloud account. This is a known limitation and must be budgeted for during development.
- Each environment (dev, staging, prod) needs its own OAuth app registration.
- Test data created during development exists in the real MF Cloud account.
- Use a dedicated development MF Cloud account to avoid polluting customer data.
Region #
MoneyForward Cloud operates Japan only. There is a single global API endpoint with no regional split.
Rate Limits #
Refer to the MoneyForward API documentation for current rate limit policies. The Cloud Accounting API applies per-endpoint rate limits.
Future Products (Post-MVP) #
The following MF Cloud products use separate legacy OAuth servers and will require independent OAuth app registrations if integrated:
| Product | Auth Server | Status |
|---|---|---|
| Cloud Expense (クラウド経費) | https://expense.moneyforward.com/oauth/ |
Post-MVP |
| Cloud Accounts Payable (クラウド債務支払) | https://payable.moneyforward.com/oauth/ |
Post-MVP |
Troubleshooting #
“Invalid Redirect URI” during OAuth #
- Verify the redirect URI in the MF App Portal matches exactly (including protocol and trailing slashes).
- Check that the bonsapi host in the environment matches the registered redirect URI.
Token Refresh Fails #
- Refresh tokens are single-use. If a refresh was attempted but the response was not persisted (e.g., crash mid-refresh), the old refresh token is already invalidated.
- The user must re-authorize through the OAuth flow.
- Check that both
access_tokenandrefresh_tokenare saved after every refresh.
403 on API Calls #
- Verify the requested scope was included in the OAuth authorization.
- Check that the MF Cloud account has the required product subscription active.
See Also #
- Setting Up Integrations (Preview) — OAuth setup for preview environments
- Secrets Management — Doppler key management
- API Integration Guide — BonsAI integration API endpoints