frappe-agent-architect
Use when designing multi-app Frappe architectures, deciding whether to split functionality into separate apps, or implementing cross-app communication…
Use when creating Frappe Whitelisted Methods (Python API endpoints) for v14/v15/v16. Covers @frappe.whitelist() decorator, frappe.call/frm.call invocations, permission checks, error handling, response formats, and client-server communication. Keywords: whitelisted, API endpoint,
$ npx -y skills add Impertio-Studio/Frappe_Claude_Skill_Package --skill frappe-syntax-whitelisted --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/frappe-syntax-whitelistedContext preview
The summary Claude sees to decide when to auto-load this skill.
Use when creating Frappe Whitelisted Methods (Python API endpoints) for v14/v15/v16. Covers @frappe.whitelist() decorator, frappe.call/frm.call invocations, permission checks, error handling, response formats, and client-server communication. Keywords: whitelisted, API endpoint,
name: frappe-syntax-whitelisted description: > Use when creating Frappe Whitelisted Methods (Python API endpoints) for v14/v15/v16. Covers @frappe.whitelist() decorator, frappe.call/frm.call invocations, permission checks, error handling, response formats, and client-server communication. Keywords: whitelisted, API endpoint, frappe.call, frm.call, REST API, @frappe.whitelist, allow_guest, API endpoint example, frappe.whitelist syntax, how to expose function. license: MIT compatibility: "Claude Code, Claude.ai Projects, Claude API. Frappe v14-v16." metadata: author: OpenAEC-Foundation version: "2.0"
Whitelisted methods expose Python functions as HTTP API endpoints via `/api/method/`.
import frappe
from frappe import _
# Authenticated endpoint (default)
@frappe.whitelist()
def get_customer_summary(customer):
frappe.has_permission("Customer", "read", throw=True)
return frappe.get_doc("Customer", customer).as_dict()
# Public endpoint — ALWAYS validate input thoroughly
@frappe.whitelist(allow_guest=True, methods=["POST"])
def submit_contact(name, email, message):
if not name or not email:
frappe.throw(_("Name and email required"), frappe.ValidationError)
return {"success": True}
# Controller method — called via frm.call('method_name')
class SalesOrder(Document):
@frappe.whitelist()
def calculate_taxes(self, include_shipping=False):
return {"tax": self.grand_total * 0.21}**Endpoint URL**: `/api/method/myapp.module.function_name`
---
@frappe.whitelist(
allow_guest=False, # True = accessible without login
xss_safe=False, # True = do NOT escape HTML in response
methods=None, # ["GET"], ["POST"], or ["GET","POST"] — default: all
force_types=None # True = require type annotations [v15+]
)| Parameter | Default | Effect | |-----------|---------|--------| | `allow_guest` | `False` | `True` = Guest role can call; ALWAYS add extra input validation | | `xss_safe` | `False` | `True` = HTML not escaped; NEVER use without sanitized output | | `methods` | `None` (all) | Restrict allowed HTTP verbs | | `force_types` | `None` | `True` = all params MUST have type annotations [v15+] |
Full details: [decorator-options.md](references/decorator-options.md)
---
What kind of endpoint?
|
+-- Standalone API (utility, integration, dashboard)?
| --> @frappe.whitelist() on a module-level function
| --> Call via: frappe.call('myapp.api.function')
| --> URL: /api/method/myapp.api.function
|
+-- Document-specific action?
| --> @frappe.whitelist() on a Document class method
| --> Call via: frm.call('method_name')
| --> URL: /api/method/run_doc_method (internal)
|
+-- Server Script (no-code)?
--> Use Server Script DocType instead (no decorator needed)
Who may call the API?
|
+-- Anyone (including guests)?
| --> allow_guest=True + thorough input validation + rate limiting
|
+-- Logged-in users only?
+-- Specific role? --> frappe.only_for("RoleName")
+-- DocType-level? --> frappe.has_permission(doctype, ptype, throw=True)
+-- Document-level? --> frappe.has_permission(doctype, ptype, doc, throw=True)
Which HTTP methods?
|
+-- Read only? --> methods=["GET"]
+-- Write only? --> methods=["POST"]
+-- Both? --> methods=["GET","POST"] or default---
ALWAYS check permissions inside every whitelisted method. The `@frappe.whitelist()` decorator only verifies the user is logged in — it does NOT check DocType or document-level permissions.
# DocType-level permission (throw=True raises PermissionError automatically)
@frappe.whitelist()
def get_orders():
frappe.has_permission("Sales Order", "read", throw=True)
return frappe.get_all("Sales Order", limit=20)
# Document-level permission
@frappe.whitelist()
def get_order(name):
frappe.has_permission("Sales Order", "read", name, throw=True)
return frappe.get_doc("Sales Order", name).as_dict()
# Role-based restriction
@frappe.whitelist()
def admin_action():
frappe.only_for("System Manager") # throws if user lacks role
return {"secret": "data"}Full patterns: [permission-patterns.md](references/permission-patterns.md)
---
Parameters arrive as **strings** from HTTP requests. ALWAYS convert explicitly.
@frappe.whitelist()
def calculate(amount, quantity, items=None):
amount = float(amount) # ALWAYS cast numeric params
quantity = int(quantity)
if isinstance(items, str): # ALWAYS parse JSON strings
items = frappe.parse_json(items)
return amount * quantityAccess all request parameters via `frappe.form_dict`:
@frappe.whitelist()
def dynamic_handler():
all_params = frappe.form_dict
customer = frappe.form_dict.get("customer")Frappe v15+ validates type annotations automatically at request time via Pydantic:
@frappe.whitelist()
def get_orders(customer: str, limit: int = 10, active: bool = True) -> dict:
# Frappe auto-validates: limit MUST be convertible to int
return {"orders": frappe.get_all("Sales Order", limit=limit)}Full details: [parameter-handling.md](references/parameter-handling.md)
---
// Promise-based (ALWAYS prefer this)
frappe.call({
method: 'myapp.api.get_summary',
args: { customer: 'CUST-001' },
freeze: true,
freeze_message: __('Loading...')
}).then(r => {
console.log(r.message); // return value is in r.message
}).catch(err => {60 deterministic Claude AI skills for Frappe Framework & ERPNext v14-v16 development and operations
Repo: Impertio-Studio/Frappe_Claude_Skill_Package
Use when designing multi-app Frappe architectures, deciding whether to split functionality into separate apps, or implementing cross-app communication…
Use when debugging Frappe errors, using bench console for live inspection, analyzing tracebacks, or reading Frappe log files. Prevents wasted debugging time…
Use when receiving vague or unclear ERPNext/Frappe development requests that need interpretation. Transforms requirements like 'make invoice auto-calculate' or…
Use when migrating a Frappe app between major versions, detecting breaking API changes, or resolving post-migration errors. Prevents failed migrations from…
Use when reviewing or validating Frappe/ERPNext code against best practices and common pitfalls. Checks generated code before deployment, validates against all…
Use when building ERPNext/Frappe API integrations (v14/v15/v16) including REST API, RPC API, authentication, webhooks, and rate limiting. Covers external API…