xero-accounting
Xero会計システムと連携し、請求書や経費、銀行取引などのデータを同期したり、損益計算書や貸借対照表といった財務諸表を自動で作成したりすることで、会計業務を効率化するSkill。
📜 元の英語説明(参考)
Integrate with the Xero accounting API to sync invoices, expenses, bank transactions, and contacts — and generate financial reports like P&L and balance sheet. Use when: connecting apps to Xero, automating bookkeeping workflows, syncing accounting data, or pulling financial reports programmatically.
🇯🇵 日本人クリエイター向け解説
Xero会計システムと連携し、請求書や経費、銀行取引などのデータを同期したり、損益計算書や貸借対照表といった財務諸表を自動で作成したりすることで、会計業務を効率化するSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o xero-accounting.zip https://jpskill.com/download/15578.zip && unzip -o xero-accounting.zip && rm xero-accounting.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/15578.zip -OutFile "$d\xero-accounting.zip"; Expand-Archive "$d\xero-accounting.zip" -DestinationPath $d -Force; ri "$d\xero-accounting.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
xero-accounting.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
xero-accountingフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 1
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
Xero Accounting
概要
Xero API を介して、アプリケーションを Xero の会計プラットフォームと統合します。この Skill では、OAuth2 認証、主要な会計オブジェクト (請求書、請求書、経費、連絡先、銀行取引) の同期、および財務レポート (損益計算書、貸借対照表、試算表) の取得について説明します。ワンタイムインポートと継続的な同期パターンの両方をサポートします。
手順
ステップ 1: OAuth2 認証の設定
Xero は PKCE を使用した OAuth2 を使用します。developer.xero.com でアプリを登録し、トークンフローを実装します。
# xero_auth.py — Xero API の OAuth2 トークン管理
import requests
import base64
import json
import os
from datetime import datetime, timedelta
XERO_CLIENT_ID = os.environ["XERO_CLIENT_ID"]
XERO_CLIENT_SECRET = os.environ["XERO_CLIENT_SECRET"]
XERO_REDIRECT_URI = os.environ["XERO_REDIRECT_URI"]
TOKEN_FILE = ".xero_tokens.json"
def get_auth_url():
"""OAuth2 認証 URL を生成します。"""
import secrets
state = secrets.token_urlsafe(16)
params = {
"response_type": "code",
"client_id": XERO_CLIENT_ID,
"redirect_uri": XERO_REDIRECT_URI,
"scope": "openid profile email accounting.transactions accounting.reports.read accounting.contacts offline_access",
"state": state,
}
query = "&".join(f"{k}={v}" for k, v in params.items())
return f"https://login.xero.com/identity/connect/authorize?{query}"
def exchange_code_for_tokens(code: str) -> dict:
"""認証コードをアクセス + リフレッシュトークンと交換します。"""
credentials = base64.b64encode(
f"{XERO_CLIENT_ID}:{XERO_CLIENT_SECRET}".encode()
).decode()
response = requests.post(
"https://identity.xero.com/connect/token",
headers={
"Authorization": f"Basic {credentials}",
"Content-Type": "application/x-www-form-urlencoded",
},
data={
"grant_type": "authorization_code",
"code": code,
"redirect_uri": XERO_REDIRECT_URI,
},
)
tokens = response.json()
tokens["expires_at"] = (
datetime.utcnow() + timedelta(seconds=tokens["expires_in"])
).isoformat()
save_tokens(tokens)
return tokens
def refresh_access_token(tokens: dict) -> dict:
"""リフレッシュトークンを使用してアクセストークンを更新します。"""
credentials = base64.b64encode(
f"{XERO_CLIENT_ID}:{XERO_CLIENT_SECRET}".encode()
).decode()
response = requests.post(
"https://identity.xero.com/connect/token",
headers={
"Authorization": f"Basic {credentials}",
"Content-Type": "application/x-www-form-urlencoded",
},
data={
"grant_type": "refresh_token",
"refresh_token": tokens["refresh_token"],
},
)
new_tokens = response.json()
new_tokens["expires_at"] = (
datetime.utcnow() + timedelta(seconds=new_tokens["expires_in"])
).isoformat()
save_tokens(new_tokens)
return new_tokens
def get_valid_token() -> str:
"""有効なアクセストークンを返します。必要に応じて更新します。"""
tokens = load_tokens()
expires_at = datetime.fromisoformat(tokens["expires_at"])
if datetime.utcnow() >= expires_at - timedelta(minutes=5):
tokens = refresh_access_token(tokens)
return tokens["access_token"]
def get_tenant_id(access_token: str) -> str:
"""Xero 組織 (テナント) ID を取得します。"""
response = requests.get(
"https://api.xero.com/connections",
headers={"Authorization": f"Bearer {access_token}"},
)
connections = response.json()
return connections[0]["tenantId"] # 最初に接続された組織を使用
def save_tokens(tokens: dict):
with open(TOKEN_FILE, "w") as f:
json.dump(tokens, f)
def load_tokens() -> dict:
with open(TOKEN_FILE) as f:
return json.load(f)
ステップ 2: API クライアントの作成
# xero_client.py — 再利用可能な Xero API クライアント
import requests
from xero_auth import get_valid_token, get_tenant_id
class XeroClient:
BASE_URL = "https://api.xero.com/api.xro/2.0"
def __init__(self):
self.token = get_valid_token()
self.tenant_id = get_tenant_id(self.token)
def _headers(self):
return {
"Authorization": f"Bearer {self.token}",
"Xero-Tenant-Id": self.tenant_id,
"Accept": "application/json",
"Content-Type": "application/json",
}
def get(self, endpoint: str, params: dict = None) -> dict:
response = requests.get(
f"{self.BASE_URL}/{endpoint}",
headers=self._headers(),
params=params,
)
response.raise_for_status()
return response.json()
def post(self, endpoint: str, data: dict) -> dict:
response = requests.post(
f"{self.BASE_URL}/{endpoint}",
headers=self._headers(),
json=data,
)
response.raise_for_status()
return response.json()
def put(self, endpoint: str, data: dict) -> dict:
response = requests.put(
f"{self.BASE_URL}/{endpoint}",
headers=self._headers(),
json=data,
)
response.raise_for_status()
return response.json()
ステップ 3: 請求書の同期
# sync_invoices.py — Xero での請求書の作成と取得
from xero_client import XeroClient
from datetime import datetime
client = XeroClient()
def create_invoice(contact_name: str, line_items: list, due_date: str, currency: str = "USD") -> dict:
"""
Xero で売上請求書 (ACCREC) を作成します。
line_items の形式:
[{"description": "...", "quantity": 1, "unitAmount": 100.0, "accountCode": "200"}]
"""
payload = {
"Invoices": [{
"Type": "ACCREC",
"Contact": {"Name": contact_name},
"DueDate": due_date, # 例: "2025-03-31"
"CurrencyCode": currency,
"LineItems": [
{
(原文がここで切り詰められています) 📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
Xero Accounting
Overview
Integrate your application with Xero's accounting platform via the Xero API. This skill covers OAuth2 authentication, syncing core accounting objects (invoices, bills, expenses, contacts, bank transactions), and pulling financial reports (P&L, balance sheet, trial balance). Supports both one-time imports and continuous sync patterns.
Instructions
Step 1: Set up OAuth2 authentication
Xero uses OAuth2 with PKCE. Register your app at developer.xero.com, then implement the token flow:
# xero_auth.py — OAuth2 token management for Xero API
import requests
import base64
import json
import os
from datetime import datetime, timedelta
XERO_CLIENT_ID = os.environ["XERO_CLIENT_ID"]
XERO_CLIENT_SECRET = os.environ["XERO_CLIENT_SECRET"]
XERO_REDIRECT_URI = os.environ["XERO_REDIRECT_URI"]
TOKEN_FILE = ".xero_tokens.json"
def get_auth_url():
"""Generate the OAuth2 authorization URL."""
import secrets
state = secrets.token_urlsafe(16)
params = {
"response_type": "code",
"client_id": XERO_CLIENT_ID,
"redirect_uri": XERO_REDIRECT_URI,
"scope": "openid profile email accounting.transactions accounting.reports.read accounting.contacts offline_access",
"state": state,
}
query = "&".join(f"{k}={v}" for k, v in params.items())
return f"https://login.xero.com/identity/connect/authorize?{query}"
def exchange_code_for_tokens(code: str) -> dict:
"""Exchange authorization code for access + refresh tokens."""
credentials = base64.b64encode(
f"{XERO_CLIENT_ID}:{XERO_CLIENT_SECRET}".encode()
).decode()
response = requests.post(
"https://identity.xero.com/connect/token",
headers={
"Authorization": f"Basic {credentials}",
"Content-Type": "application/x-www-form-urlencoded",
},
data={
"grant_type": "authorization_code",
"code": code,
"redirect_uri": XERO_REDIRECT_URI,
},
)
tokens = response.json()
tokens["expires_at"] = (
datetime.utcnow() + timedelta(seconds=tokens["expires_in"])
).isoformat()
save_tokens(tokens)
return tokens
def refresh_access_token(tokens: dict) -> dict:
"""Refresh the access token using the refresh token."""
credentials = base64.b64encode(
f"{XERO_CLIENT_ID}:{XERO_CLIENT_SECRET}".encode()
).decode()
response = requests.post(
"https://identity.xero.com/connect/token",
headers={
"Authorization": f"Basic {credentials}",
"Content-Type": "application/x-www-form-urlencoded",
},
data={
"grant_type": "refresh_token",
"refresh_token": tokens["refresh_token"],
},
)
new_tokens = response.json()
new_tokens["expires_at"] = (
datetime.utcnow() + timedelta(seconds=new_tokens["expires_in"])
).isoformat()
save_tokens(new_tokens)
return new_tokens
def get_valid_token() -> str:
"""Return a valid access token, refreshing if needed."""
tokens = load_tokens()
expires_at = datetime.fromisoformat(tokens["expires_at"])
if datetime.utcnow() >= expires_at - timedelta(minutes=5):
tokens = refresh_access_token(tokens)
return tokens["access_token"]
def get_tenant_id(access_token: str) -> str:
"""Get the Xero organisation (tenant) ID."""
response = requests.get(
"https://api.xero.com/connections",
headers={"Authorization": f"Bearer {access_token}"},
)
connections = response.json()
return connections[0]["tenantId"] # Use first connected org
def save_tokens(tokens: dict):
with open(TOKEN_FILE, "w") as f:
json.dump(tokens, f)
def load_tokens() -> dict:
with open(TOKEN_FILE) as f:
return json.load(f)
Step 2: Create an API client
# xero_client.py — Reusable Xero API client
import requests
from xero_auth import get_valid_token, get_tenant_id
class XeroClient:
BASE_URL = "https://api.xero.com/api.xro/2.0"
def __init__(self):
self.token = get_valid_token()
self.tenant_id = get_tenant_id(self.token)
def _headers(self):
return {
"Authorization": f"Bearer {self.token}",
"Xero-Tenant-Id": self.tenant_id,
"Accept": "application/json",
"Content-Type": "application/json",
}
def get(self, endpoint: str, params: dict = None) -> dict:
response = requests.get(
f"{self.BASE_URL}/{endpoint}",
headers=self._headers(),
params=params,
)
response.raise_for_status()
return response.json()
def post(self, endpoint: str, data: dict) -> dict:
response = requests.post(
f"{self.BASE_URL}/{endpoint}",
headers=self._headers(),
json=data,
)
response.raise_for_status()
return response.json()
def put(self, endpoint: str, data: dict) -> dict:
response = requests.put(
f"{self.BASE_URL}/{endpoint}",
headers=self._headers(),
json=data,
)
response.raise_for_status()
return response.json()
Step 3: Sync invoices
# sync_invoices.py — Create and retrieve invoices in Xero
from xero_client import XeroClient
from datetime import datetime
client = XeroClient()
def create_invoice(contact_name: str, line_items: list, due_date: str, currency: str = "USD") -> dict:
"""
Create a sales invoice (ACCREC) in Xero.
line_items format:
[{"description": "...", "quantity": 1, "unitAmount": 100.0, "accountCode": "200"}]
"""
payload = {
"Invoices": [{
"Type": "ACCREC",
"Contact": {"Name": contact_name},
"DueDate": due_date, # e.g. "2025-03-31"
"CurrencyCode": currency,
"LineItems": [
{
"Description": item["description"],
"Quantity": item["quantity"],
"UnitAmount": item["unitAmount"],
"AccountCode": item.get("accountCode", "200"),
}
for item in line_items
],
"Status": "AUTHORISED",
}]
}
result = client.post("Invoices", payload)
invoice = result["Invoices"][0]
print(f"Created invoice {invoice['InvoiceNumber']} — Total: {invoice['Total']}")
return invoice
def list_invoices(status: str = "AUTHORISED", modified_since: str = None) -> list:
"""Retrieve invoices, optionally filtered by status or modified date."""
params = {"Status": status}
headers_extra = {}
if modified_since:
headers_extra["If-Modified-Since"] = modified_since
result = client.get("Invoices", params=params)
return result.get("Invoices", [])
def mark_invoice_paid(invoice_id: str, amount: float, account_code: str = "090") -> dict:
"""Record a payment against an invoice."""
payload = {
"Payments": [{
"Invoice": {"InvoiceID": invoice_id},
"Account": {"Code": account_code},
"Amount": amount,
"Date": datetime.utcnow().strftime("%Y-%m-%d"),
}]
}
result = client.post("Payments", payload)
return result["Payments"][0]
Step 4: Sync bank transactions
# sync_bank_transactions.py — Push bank transactions into Xero
from xero_client import XeroClient
client = XeroClient()
def create_bank_transaction(
account_id: str,
contact_name: str,
amount: float,
date: str,
description: str,
account_code: str = "400",
tx_type: str = "SPEND", # SPEND or RECEIVE
) -> dict:
"""Record a bank transaction (spend or receive money)."""
payload = {
"BankTransactions": [{
"Type": tx_type,
"Contact": {"Name": contact_name},
"BankAccount": {"AccountID": account_id},
"Date": date,
"LineItems": [{
"Description": description,
"Quantity": 1,
"UnitAmount": abs(amount),
"AccountCode": account_code,
}],
"IsReconciled": False,
}]
}
result = client.post("BankTransactions", payload)
return result["BankTransactions"][0]
def bulk_import_transactions(account_id: str, transactions: list) -> list:
"""
Import multiple bank transactions in a single API call.
transactions: list of dicts with keys:
date, contact, amount (negative=spend, positive=receive), description, account_code
"""
bank_txs = []
for tx in transactions:
tx_type = "SPEND" if tx["amount"] < 0 else "RECEIVE"
bank_txs.append({
"Type": tx_type,
"Contact": {"Name": tx["contact"]},
"BankAccount": {"AccountID": account_id},
"Date": tx["date"],
"LineItems": [{
"Description": tx["description"],
"Quantity": 1,
"UnitAmount": abs(tx["amount"]),
"AccountCode": tx.get("account_code", "400"),
}],
})
payload = {"BankTransactions": bank_txs}
result = client.post("BankTransactions", payload)
created = result["BankTransactions"]
print(f"Imported {len(created)} bank transactions")
return created
Step 5: Generate financial reports
# reports.py — Pull P&L and balance sheet from Xero
from xero_client import XeroClient
client = XeroClient()
def get_profit_and_loss(from_date: str, to_date: str) -> dict:
"""
Fetch Profit & Loss report.
Dates format: YYYY-MM-DD
"""
params = {
"fromDate": from_date,
"toDate": to_date,
}
result = client.get("Reports/ProfitAndLoss", params=params)
report = result["Reports"][0]
# Parse rows into a flat dict
summary = {}
for row in report.get("Rows", []):
if row.get("RowType") == "SummaryRow":
cells = row.get("Cells", [])
if len(cells) >= 2:
summary[cells[0].get("Value", "")] = cells[1].get("Value", "")
return {"raw": report, "summary": summary}
def get_balance_sheet(date: str) -> dict:
"""Fetch Balance Sheet as of a given date (YYYY-MM-DD)."""
result = client.get("Reports/BalanceSheet", params={"date": date})
return result["Reports"][0]
def get_trial_balance(date: str) -> list:
"""Fetch Trial Balance as of a given date."""
result = client.get("Reports/TrialBalance", params={"date": date})
report = result["Reports"][0]
rows = []
for row in report.get("Rows", []):
if row.get("RowType") == "Row":
cells = row.get("Cells", [])
if cells:
rows.append({
"account": cells[0].get("Value"),
"debit": cells[1].get("Value") if len(cells) > 1 else None,
"credit": cells[2].get("Value") if len(cells) > 2 else None,
"ytd_debit": cells[3].get("Value") if len(cells) > 3 else None,
"ytd_credit": cells[4].get("Value") if len(cells) > 4 else None,
})
return rows
Step 6: Manage contacts
# contacts.py — Create and update Xero contacts (customers and suppliers)
from xero_client import XeroClient
client = XeroClient()
def upsert_contact(name: str, email: str = None, phone: str = None,
is_customer: bool = True, is_supplier: bool = False) -> dict:
"""Create or update a contact in Xero."""
contact = {
"Name": name,
"IsCustomer": is_customer,
"IsSupplier": is_supplier,
}
if email:
contact["EmailAddress"] = email
if phone:
contact["Phones"] = [{"PhoneType": "DEFAULT", "PhoneNumber": phone}]
payload = {"Contacts": [contact]}
result = client.post("Contacts", payload)
return result["Contacts"][0]
def find_contact_by_email(email: str) -> dict | None:
"""Look up a contact by email address."""
result = client.get("Contacts", params={"EmailAddress": email})
contacts = result.get("Contacts", [])
return contacts[0] if contacts else None
Examples
Example 1: Sync Stripe payment as Xero invoice
# When a Stripe payment succeeds, create a matching Xero invoice and mark it paid
stripe_payment = {
"customer_email": "client@example.com",
"amount": 2500.00,
"currency": "USD",
"description": "Monthly SaaS subscription — March 2025",
"date": "2025-03-01",
}
contact = upsert_contact(
name=stripe_payment["customer_email"],
email=stripe_payment["customer_email"],
is_customer=True,
)
invoice = create_invoice(
contact_name=contact["Name"],
line_items=[{
"description": stripe_payment["description"],
"quantity": 1,
"unitAmount": stripe_payment["amount"],
"accountCode": "200",
}],
due_date=stripe_payment["date"],
currency=stripe_payment["currency"].upper(),
)
mark_invoice_paid(invoice["InvoiceID"], amount=stripe_payment["amount"])
print(f"Synced invoice {invoice['InvoiceNumber']} to Xero ✓")
Example 2: Generate monthly P&L and print summary
pnl = get_profit_and_loss("2025-03-01", "2025-03-31")
print("March 2025 P&L Summary")
print("=" * 30)
for label, value in pnl["summary"].items():
print(f" {label:<20} {value:>12}")
Output:
March 2025 P&L Summary
==============================
Total Income $18,500.00
Total Cost of Sales $3,200.00
Gross Profit $15,300.00
Total Expenses $6,750.00
Net Profit $8,550.00
Environment Variables
| Variable | Description |
|---|---|
XERO_CLIENT_ID |
OAuth2 client ID from Xero developer portal |
XERO_CLIENT_SECRET |
OAuth2 client secret |
XERO_REDIRECT_URI |
Callback URL registered in Xero app |
Guidelines
- Always refresh the access token before making API calls — Xero tokens expire after 30 minutes.
- Use
If-Modified-Sinceheaders on GET requests to sync only updated records. - Xero rate limits: 60 calls/minute per tenant. Batch writes (e.g. multiple invoices in one POST) to stay within limits.
- Account codes (e.g. "200" for Revenue, "400" for Expenses) vary by organization — confirm the chart of accounts before hardcoding.
- For production, store tokens in a database or secrets manager, not in a local file.
- Use
AUTHORISEDstatus for invoices to make them visible in Xero's UI immediately. - The Xero sandbox (demo company) is available at
https://api.xero.com— connect it during OAuth to test without affecting real data.