If you are evaluating Frappe as the base for a custom business application, one early question is how other systems will talk to it. The short answer: Frappe exposes every DocType over a REST API automatically, so you get working endpoints before you write any API code.
The short version: Frappe’s REST API has three pieces. You authenticate with an API key and secret (token auth), a session cookie, or OAuth 2. You read and write documents through /api/resource/{DocType}. And you call your own server-side functions, marked as whitelisted, through /api/method/{path}. Every call runs with the permissions of the authenticated user.
That last sentence matters more than it looks, and we will come back to it. First, the mechanics.
What "REST API" means in Frappe
Frappe is a framework, not just an ERP. When you define a DocType (a Frappe data model with its form, validations and permissions), the framework generates database tables, a UI, and API endpoints for it. You do not write controllers or routes for basic create, read, update and delete.
For a CTO, the practical consequence is that your API surface and your data model grow together. Add a field to a DocType, and it is available over the API once the schema migrates. For a non-technical founder, this means integrations with a website, a mobile app or a third-party tool do not need to wait for a separate “API project”.
Frappe API authentication: three ways in
Token authentication(API key and secret)
Authorization: token :
Session authentication
/api/method/login, and Frappe returns a session cookie. Later requests carry that cookie. State-changing requests made from a browser session also need a CSRF token. Token auth skips this, which is one reason it suits backend integrations better.OAuth 2
Frappe API endpoints you will use most
| Endpoint | Method | What it does |
|---|---|---|
/api/resource/{DocType} | GET | List documents, with filtering and field selection |
/api/resource/{DocType} | POST | Create a document |
/api/resource/{DocType}/{name} | GET | Read one document, including its child table rows |
/api/resource/{DocType}/{name} | PUT | Update fields on a document |
/api/resource/{DocType}/{name} | DELETE | Delete a document |
/api/method/{dotted.path} | GET / POST | Call a whitelisted server-side function |
data key. Method calls return theirs under message. It is a small difference that trips up many first integrations.Listing and filtering
fields, filters, order_by, limit_start and limit_page_length. Filters are passed as a JSON-encoded list. A request for open sales orders for one customer, with only three fields returned, looks like this:
GET /api/resource/Sales Order
?fields=["name","customer","grand_total"]
&filters=[["customer","=","Acme Traders"],["status","=","To Deliver and Bill"]]
&limit_page_length=50
Creating and updating documents
A POST to /api/resource/{DocType} with a JSON body creates a document. Frappe runs the same validations it runs when a user saves the form: mandatory fields, link checks, naming rules and any custom validation in the DocType controller. If a validation fails, the API returns an error with the message the form would have shown. Check the response body rather than relying on the status code alone, since validation failures do not always arrive as the status code a REST purist would expect.
Child tables are sent as nested arrays inside the parent document. An invoice with line items is one request, not many.
Calling your own methods
This is where a custom Frappe app starts to differ from plain CRUD. You write a Python function and decorate it with @frappe.whitelist(). Frappe then exposes it at /api/method/your_app.module.function_name.
Use methods when the operation is a business action rather than a data edit: “approve this requisition”, “reserve stock for this order”, “return the delivery slots for this pincode”. Wrapping that logic in one method keeps the rules on the server, where you can test them, instead of scattered across client applications.
Permissions: your API is only as safe as your roles
Every REST call runs as the authenticated user, and Frappe applies that user’s role permissions and any user permissions (record-level restrictions) before it returns or changes data. There is no separate API permission layer to configure.
This is good news if you have already modelled roles properly. It also means weak role design shows up in your API first. A few habits help:
Create one integration user per external system, not one shared key.
Give each user only the roles the integration needs.
Mark methods as whitelisted deliberately, and check permissions inside them where the action is sensitive. Whitelisting makes a function callable; it does not decide who should call it.
Rotate keys when staff or vendors change.
Common use cases
Website or app front end. A customer portal, mobile app or storefront reads items and prices and posts orders into Frappe.
Third-party system sync. Pushing shipment status from a courier, payments from a gateway, or attendance from a device into the matching DocTypes.
Reporting and BI. Pulling filtered lists into a data tool on a schedule.
Workflow triggers. An external system calls a whitelisted method that moves a document through its workflow.
Migration scripts. Bulk creation of masters and opening balances, which then pass the same validation as manual entry.
Where this gets harder than the basics
Newer Frappe releases add API versions and options beyond what is covered here, so check the documentation for the version you run.
One request per document is simple but slow for large loads. Batch sensibly and test with realistic volumes.
Retried POST calls can create duplicates unless your integration checks first or you design the method to be safe to repeat.
Treat validation messages as part of the contract with your integration, and log them.
If your project goes beyond reading and writing documents, such as custom whitelisted methods, background jobs or a mobile app on top of Frappe, that is the territory of custom Frappe apps. Teams weighing the framework itself can read more about Frappe framework development before committing to an approach.
If you are mapping out an integration and want a second pair of eyes on the endpoint design, a short conversation with an engineer usually saves rework later.
Frequently Asked Questions
Yes. Every DocType gets resource endpoints under /api/resource/, and any function you whitelist is callable under /api/method/. No extra module needs installing.
For backend integrations, generate an API key and secret on a user and send Authorization: token key:secret. Use session login for browser flows and OAuth 2 when third-party apps act for users.
Yes. Write a Python function, decorate it with @frappe.whitelist(), and call it at /api/method/ followed by its dotted path. Add permission checks inside for sensitive actions.
Next step
If you are weighing Frappe for a custom application and want to talk through how the API fits your integrations, talk to our Frappe development team. We can review your data model and integration list and tell you plainly where the framework helps and where extra engineering is needed.






