Skip to content

Commit 0009b0c

Browse files
committed
fix: convert amount_spent and balance from cents to currency units in get_ad_accounts and get_account_info
Meta API returns amount_spent and balance as integers in the smallest currency unit (cents for USD/EUR/AUD etc). The raw integer was passed through directly, causing get_ad_accounts to return 40438 instead of 404.38 for a USD account. get_insights already returns spend in currency units so this was inconsistent. Added _cents_to_currency helper with a zero-decimal currency set (JPY, KRW, etc.) and applied it to both tools.
1 parent 4e95d24 commit 0009b0c

File tree

1 file changed

+45
-4
lines changed

1 file changed

+45
-4
lines changed

meta_ads_mcp/core/accounts.py

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,49 @@
55
from .api import meta_api_tool, make_api_request
66
from .server import mcp_server
77

8+
# Currencies that have no sub-units (i.e., are not denominated in cents).
9+
# Meta API returns amount_spent and balance as integers in the smallest currency
10+
# unit, which is cents for most currencies but the base unit for these.
11+
_ZERO_DECIMAL_CURRENCIES = {
12+
"BIF", "CLP", "DJF", "GNF", "JPY", "KMF", "KRW", "MGA",
13+
"PYG", "RWF", "UGX", "VND", "VUV", "XAF", "XOF", "XPF",
14+
}
15+
16+
17+
def _cents_to_currency(amount, currency: str) -> str:
18+
"""Convert a Meta API monetary value (cents) to a currency-unit string.
19+
20+
Meta returns amount_spent and balance as integers representing the smallest
21+
currency unit (cents for USD/EUR/GBP, base unit for zero-decimal currencies
22+
like JPY). This converts to the human-readable decimal amount.
23+
"""
24+
try:
25+
amount_int = int(amount)
26+
except (TypeError, ValueError):
27+
return str(amount)
28+
if currency.upper() in _ZERO_DECIMAL_CURRENCIES:
29+
return str(amount_int)
30+
return f"{amount_int / 100:.2f}"
31+
32+
33+
def _normalize_account_monetary_fields(account: dict) -> dict:
34+
"""Convert amount_spent and balance from cents to currency units in-place."""
35+
currency = account.get("currency", "USD")
36+
for field in ("amount_spent", "balance"):
37+
if field in account:
38+
account[field] = _cents_to_currency(account[field], currency)
39+
return account
40+
841

942
@mcp_server.tool()
1043
@meta_api_tool
1144
async def get_ad_accounts(access_token: Optional[str] = None, user_id: str = "me", limit: int = 200) -> str:
1245
"""
1346
Get ad accounts accessible by a user.
14-
47+
48+
amount_spent and balance are returned in currency units (e.g. USD dollars),
49+
not cents.
50+
1551
Args:
1652
access_token: Meta API access token (optional - will use cached token if not provided)
1753
user_id: Meta user ID or "me" for the current user
@@ -22,9 +58,12 @@ async def get_ad_accounts(access_token: Optional[str] = None, user_id: str = "me
2258
"fields": "id,name,account_id,account_status,amount_spent,balance,currency,age,business_city,business_country_code",
2359
"limit": limit
2460
}
25-
61+
2662
data = await make_api_request(endpoint, access_token, params)
27-
63+
64+
if "data" in data:
65+
data["data"] = [_normalize_account_monetary_fields(acc) for acc in data["data"]]
66+
2867
return json.dumps(data, indent=2)
2968

3069

@@ -58,7 +97,7 @@ async def get_account_info(account_id: str, access_token: Optional[str] = None)
5897
}
5998

6099
data = await make_api_request(endpoint, access_token, params)
61-
100+
62101
# Check if the API request returned an error
63102
if "error" in data:
64103
# If access was denied, provide helpful error message with accessible accounts
@@ -89,6 +128,8 @@ async def get_account_info(account_id: str, access_token: Optional[str] = None)
89128
# Return the original error for non-permission related issues
90129
return data
91130

131+
_normalize_account_monetary_fields(data)
132+
92133
# Add DSA requirement detection
93134
if "business_country_code" in data:
94135
european_countries = ["DE", "FR", "IT", "ES", "NL", "BE", "AT", "IE", "DK", "SE", "FI", "NO"]

0 commit comments

Comments
 (0)