# Frappe Api Development

> Build REST and RPC APIs in Frappe including whitelisted methods, authentication, and permission handling. Use when creating custom endpoints, integrating with external systems, or exposing business logic via API.

- **Type:** Skill
- **Install:** `agentstack add skill-lubusin-frappe-skills-frappe-api-development`
- **Verified:** Pending review
- **Seller:** [lubusIN](https://agentstack.voostack.com/s/lubusin)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [lubusIN](https://github.com/lubusIN)
- **Source:** https://github.com/lubusIN/frappe-skills/tree/main/frappe-api-development

## Install

```sh
agentstack add skill-lubusin-frappe-skills-frappe-api-development
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Frappe API Development

Build secure, well-designed APIs using Frappe's REST and RPC patterns.

## When to use

- Creating custom RPC endpoints (`@frappe.whitelist`)
- Building REST API integrations
- Implementing webhooks for external systems
- Setting up API authentication (token, OAuth)
- Exposing business logic to frontends

## Inputs required

- API purpose (CRUD, action, integration)
- Authentication requirements (public, user, API key)
- Permission requirements per endpoint
- Request/response format expectations

## Procedure

### 0) Choose API pattern

| Need | Pattern |
|------|---------|
| DocType CRUD | Use built-in REST API |
| Custom action | RPC with `@frappe.whitelist` |
| External callback | Webhook DocType |
| Batch operations | Background job + status endpoint |

### 1) Built-in REST API (DocType CRUD)

Frappe provides automatic REST endpoints for all DocTypes:

```bash
# Create
POST /api/resource/Customer
{"customer_name": "Acme Corp"}

# Read
GET /api/resource/Customer/CUST-001

# Update
PUT /api/resource/Customer/CUST-001
{"customer_name": "Acme Corporation"}

# Delete
DELETE /api/resource/Customer/CUST-001

# List with filters
GET /api/resource/Customer?filters=[["status","=","Active"]]
```

### 2) Custom RPC endpoints

Create whitelisted methods in your app:

```python
# my_app/api.py
import frappe

@frappe.whitelist()
def process_order(order_id, action):
    """Process an order with the given action."""
    # Always verify permissions
    doc = frappe.get_doc("Sales Order", order_id)
    if not frappe.has_permission("Sales Order", "write", doc):
        frappe.throw("Not permitted", frappe.PermissionError)
    
    # Business logic
    if action == "approve":
        doc.status = "Approved"
        doc.save()
    
    return {"status": "success", "order": doc.name}

@frappe.whitelist(allow_guest=True)
def public_endpoint():
    """Public endpoint - no auth required."""
    return {"message": "Hello, World!"}
```

Call via:
```bash
POST /api/method/my_app.api.process_order
{"order_id": "SO-001", "action": "approve"}
```

### 3) Implement authentication

**API Key + Secret (recommended for integrations):**
```bash
# Header format
Authorization: token api_key:api_secret
```

**Bearer Token:**
```bash
Authorization: Bearer 
```

**Session (for logged-in users):**
Automatic via cookies.

### 4) Permission checks

**ALWAYS check permissions in RPC methods:**

```python
@frappe.whitelist()
def sensitive_action(docname):
    doc = frappe.get_doc("My DocType", docname)
    
    # Check document-level permission
    if not frappe.has_permission("My DocType", "write", doc):
        frappe.throw("Not permitted", frappe.PermissionError)
    
    # Check role-based permission
    if "Manager" not in frappe.get_roles():
        frappe.throw("Manager role required")
    
    # Proceed with action
    ...
```

### 5) Input validation

```python
@frappe.whitelist()
def create_item(name, qty, price):
    # Validate required fields
    if not name:
        frappe.throw("Name is required")
    
    # Validate types
    qty = frappe.utils.cint(qty)
    price = frappe.utils.flt(price)
    
    # Validate ranges
    if qty  console` → test endpoint manually

## Failure modes / debugging

- **Method not found**: Check module path in URL matches Python path
- **Permission denied**: Verify `@frappe.whitelist()` decorator and user permissions
- **CSRF error**: Use proper auth headers for API calls
- **500 error**: Check error logs: `bench --site  show-log`

## Escalation

- For OAuth integration, see [references/oauth.md](references/oauth.md)
- For webhook patterns, see [references/webhooks.md](references/webhooks.md)
- For rate limiting, see [references/rate-limiting.md](references/rate-limiting.md)

## References

- [references/rest-api.md](references/rest-api.md) - REST API details
- [references/authentication.md](references/authentication.md) - Auth patterns
- [references/permissions.md](references/permissions.md) - Permission system
- [references/webhooks.md](references/webhooks.md) - Outbound webhooks

## Guardrails

- **Always validate input**: Never trust client data; validate type, length, and format server-side
- **Use permission callbacks**: Check `frappe.has_permission()` explicitly in whitelisted methods
- **Sanitize user input**: Use `frappe.db.escape()` for SQL, avoid `eval()` and dynamic code execution
- **Handle rate limiting**: Implement rate limits for public APIs to prevent abuse
- **Return structured errors**: Use `frappe.throw()` with proper HTTP status codes

## Common Mistakes

| Mistake | Why It Fails | Fix |
|---------|--------------|-----|
| Missing `@frappe.whitelist()` | Method returns "Method not found" error | Add decorator to expose method via API |
| Using GET for mutations | Violates REST conventions, CSRF issues | Use POST/PUT/DELETE for data changes |
| Not handling errors | 500 errors expose stack traces | Wrap in try/except, use `frappe.throw()` |
| Exposing sensitive data | Security breach | Filter response fields, check permissions |
| Missing `allow_guest=True` | Public endpoints return 403 | Add `@frappe.whitelist(allow_guest=True)` for unauthenticated access |
| SQL injection in queries | Database compromise | Use Query Builder or `frappe.db.escape()` |

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [lubusIN](https://github.com/lubusIN)
- **Source:** [lubusIN/frappe-skills](https://github.com/lubusIN/frappe-skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** yes

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: flagged — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-lubusin-frappe-skills-frappe-api-development
- Seller: https://agentstack.voostack.com/s/lubusin
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
