frappe-api

Complete reference for Frappe's Python and JavaScript APIs for document operations, database queries, utilities, and server communication.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "frappe-api" with this command: npx skills add unityappsuite/frappe-claude/unityappsuite-frappe-claude-frappe-api

Frappe API Reference

Complete reference for Frappe's Python and JavaScript APIs for document operations, database queries, utilities, and server communication.

When to Use This Skill

  • Working with Document API (get_doc, new_doc, save)

  • Database operations (frappe.db.*)

  • Making API calls from client to server

  • Using Frappe utilities (date, number formatting)

  • Creating whitelisted API endpoints

  • Working with REST API

Python API

Document Operations

Get Document

Get existing document

doc = frappe.get_doc("Customer", "CUST-001")

Get document with filters

doc = frappe.get_doc("Customer", {"customer_name": "John"})

Get last document

doc = frappe.get_last_doc("Customer", filters={"status": "Active"})

Get cached document (read-only, faster)

doc = frappe.get_cached_doc("Customer", "CUST-001")

Check if document exists

if frappe.db.exists("Customer", "CUST-001"): doc = frappe.get_doc("Customer", "CUST-001")

Create Document

Create new document

doc = frappe.new_doc("Customer") doc.customer_name = "New Customer" doc.customer_type = "Company" doc.insert()

Create with dict

doc = frappe.get_doc({ "doctype": "Customer", "customer_name": "New Customer", "customer_type": "Company" }) doc.insert()

Create and insert in one step

doc = frappe.get_doc({ "doctype": "Customer", "customer_name": "New Customer" }).insert()

Insert ignoring permissions

doc.insert(ignore_permissions=True)

Insert ignoring mandatory fields

doc.insert(ignore_mandatory=True)

Update Document

Update and save

doc = frappe.get_doc("Customer", "CUST-001") doc.customer_name = "Updated Name" doc.save()

Save ignoring permissions

doc.save(ignore_permissions=True)

Update single value

frappe.db.set_value("Customer", "CUST-001", "customer_name", "New Name")

Update multiple values

frappe.db.set_value("Customer", "CUST-001", { "customer_name": "New Name", "status": "Active" })

Bulk update

frappe.db.set_value("Customer", {"status": "Inactive"}, "status", "Active")

Delete Document

Delete document

frappe.delete_doc("Customer", "CUST-001")

Delete ignoring permissions

frappe.delete_doc("Customer", "CUST-001", ignore_permissions=True)

Delete with linked documents

frappe.delete_doc("Customer", "CUST-001", force=True)

Delete from controller

doc.delete()

Database API (frappe.db)

Select Queries

Get single value

value = frappe.db.get_value("Customer", "CUST-001", "customer_name")

Get multiple fields

values = frappe.db.get_value("Customer", "CUST-001", ["customer_name", "status"], as_dict=True)

Get with filters

value = frappe.db.get_value("Customer", {"customer_type": "Company"}, "customer_name")

Get list of values

names = frappe.db.get_all("Customer", filters={"status": "Active"}, fields=["name", "customer_name"], order_by="creation desc", limit=10 )

Get list with pluck (single field as list)

names = frappe.db.get_all("Customer", filters={"status": "Active"}, pluck="name" )

Complex filters

docs = frappe.db.get_all("Sales Invoice", filters={ "status": ["in", ["Paid", "Unpaid"]], "grand_total": [">", 1000], "posting_date": ["between", ["2024-01-01", "2024-12-31"]], "customer": ["like", "%Corp%"] }, fields=["name", "customer", "grand_total"] )

Filter operators

=, !=, <, >, <=, >=

in, not in

like, not like

between

is, is not (for None)

descendants of, ancestors of (for tree doctypes)

Get count

count = frappe.db.count("Customer", {"status": "Active"})

Check existence

exists = frappe.db.exists("Customer", "CUST-001") exists = frappe.db.exists("Customer", {"customer_name": "John"})

Raw SQL

Execute SQL query

result = frappe.db.sql(""" SELECT name, customer_name, grand_total FROM tabSales Invoice WHERE status = %s AND grand_total > %s ORDER BY creation DESC LIMIT 10 """, ("Paid", 1000), as_dict=True)

Single value

total = frappe.db.sql(""" SELECT SUM(grand_total) FROM tabSales Invoice WHERE status = 'Paid' """)[0][0]

With named parameters

result = frappe.db.sql(""" SELECT * FROM tabCustomer WHERE name = %(name)s """, {"name": "CUST-001"}, as_dict=True)

Insert/Update

Insert raw

frappe.db.sql(""" INSERT INTO tabCustomer (name, customer_name) VALUES (%s, %s) """, ("CUST-002", "New Customer"))

Commit transaction

frappe.db.commit()

Rollback

frappe.db.rollback()

Whitelisted API

Create API endpoint

@frappe.whitelist() def get_customer_details(customer): """Get customer details

Args:
    customer: Customer ID

Returns:
    dict: Customer details
"""
doc = frappe.get_doc("Customer", customer)
return {
    "name": doc.name,
    "customer_name": doc.customer_name,
    "outstanding_amount": get_outstanding(customer)
}

Allow guest access (no login required)

@frappe.whitelist(allow_guest=True) def public_api(): return {"status": "ok"}

With specific methods

@frappe.whitelist(methods=["POST"]) def create_record(data): doc = frappe.get_doc(data) doc.insert() return doc.name

Utilities

Date/Time

from frappe.utils import ( now, nowdate, nowtime, now_datetime, today, getdate, get_datetime, add_days, add_months, add_years, date_diff, time_diff, time_diff_in_seconds, get_first_day, get_last_day, formatdate, format_datetime )

Current date/time

current = nowdate() # "2024-01-15" current_dt = now_datetime() # datetime object timestamp = now() # "2024-01-15 10:30:00"

Date arithmetic

next_week = add_days(nowdate(), 7) next_month = add_months(nowdate(), 1) last_year = add_years(nowdate(), -1)

Date difference

days = date_diff(end_date, start_date) seconds = time_diff_in_seconds(end_time, start_time)

First/last day of month

first = get_first_day(nowdate()) last = get_last_day(nowdate())

Parse dates

date_obj = getdate("2024-01-15") dt_obj = get_datetime("2024-01-15 10:30:00")

Format dates

formatted = formatdate("2024-01-15", "dd-MM-yyyy")

Numbers

from frappe.utils import ( flt, cint, cstr, fmt_money, rounded, money_in_words )

Type conversion with defaults

num = flt(value) # float, None -> 0.0 num = flt(value, 2) # with precision integer = cint(value) # int, None -> 0 string = cstr(value) # string, None -> ""

Formatting

formatted = fmt_money(1234.56, currency="USD") # "$1,234.56" rounded_val = rounded(1234.567, 2) # 1234.57 words = money_in_words(1234.56, "USD") # "One Thousand..."

Strings

from frappe.utils import ( strip_html, strip_html_tags, escape_html, sanitize_html, scrub, unscrub )

HTML handling

plain = strip_html("<p>Hello</p>") # "Hello" safe = escape_html("<script>bad</script>")

Field name conversion

field = scrub("My Field Name") # "my_field_name" label = unscrub("my_field_name") # "My Field Name"

Messaging & Notifications

Show message (appears as toast)

frappe.msgprint("Document saved successfully")

With indicator

frappe.msgprint("Error occurred", indicator="red", title="Error")

Throw error (stops execution)

frappe.throw("Invalid data provided")

With exception type

from frappe.exceptions import ValidationError frappe.throw("Validation failed", exc=ValidationError)

Send email

frappe.sendmail( recipients=["user@example.com"], subject="Hello", message="Email body", template="email_template", args={"name": "John"} )

Create system notification

frappe.publish_realtime( "msgprint", {"message": "Task completed"}, user="user@example.com" )

Background Jobs

Enqueue background job

frappe.enqueue( "myapp.tasks.heavy_task", queue="long", timeout=600, job_name="Heavy Task", customer="CUST-001" )

In tasks.py

def heavy_task(customer): # Long running task process_customer(customer)

Enqueue with callback

frappe.enqueue( method=process_data, queue="default", on_success=on_complete, on_failure=on_error )

Scheduled jobs (in hooks.py)

scheduler_events = { "daily": [ "myapp.tasks.daily_task" ], "hourly": [ "myapp.tasks.hourly_task" ], "cron": { "0 0 * * *": [ # Midnight "myapp.tasks.midnight_task" ] } }

Session & User

Current user

user = frappe.session.user

Check if logged in

if frappe.session.user != "Guest": pass

Check permissions

if frappe.has_permission("Customer", "write"): pass

Get user info

user_doc = frappe.get_doc("User", frappe.session.user) full_name = frappe.utils.get_fullname(frappe.session.user)

Check roles

if "System Manager" in frappe.get_roles(): pass

Run as different user

frappe.set_user("Administrator")

... do operations

frappe.set_user(original_user)

JavaScript API

Document Operations

// Get document frappe.call({ method: 'frappe.client.get', args: { doctype: 'Customer', name: 'CUST-001' }, callback: function(r) { console.log(r.message); } });

// Create document frappe.call({ method: 'frappe.client.insert', args: { doc: { doctype: 'Customer', customer_name: 'New Customer' } }, callback: function(r) { console.log('Created:', r.message.name); } });

// Save document frappe.call({ method: 'frappe.client.save', args: { doc: cur_frm.doc } });

// Delete document frappe.call({ method: 'frappe.client.delete', args: { doctype: 'Customer', name: 'CUST-001' } });

frappe.call (API Calls)

// Call whitelisted method frappe.call({ method: 'myapp.api.get_customer_details', args: { customer: 'CUST-001' }, freeze: true, freeze_message: 'Loading...', callback: function(r) { if (r.message) { console.log(r.message); } }, error: function(r) { frappe.msgprint('Error occurred'); } });

// Async/await pattern async function getCustomer(name) { const response = await frappe.call({ method: 'myapp.api.get_customer', args: { name } }); return response.message; }

// Call with promise frappe.call({ method: 'myapp.api.process', args: { data: 'test' } }).then(r => { console.log(r.message); });

Form API (cur_frm)

frappe.ui.form.on('Sales Invoice', { refresh: function(frm) { // Add custom button frm.add_custom_button('Process', function() { // Button action }, 'Actions');

    // Set field properties
    frm.set_df_property('field_name', 'read_only', 1);
    frm.set_df_property('field_name', 'hidden', 1);
    frm.set_df_property('field_name', 'reqd', 1);

    // Set query for link field
    frm.set_query('customer', function() {
        return {
            filters: {
                status: 'Active'
            }
        };
    });

    // Toggle fields
    frm.toggle_display('field_name', frm.doc.show_field);
    frm.toggle_reqd('field_name', frm.doc.is_required);
},

customer: function(frm) {
    // Field change handler
    if (frm.doc.customer) {
        frappe.call({
            method: 'myapp.api.get_customer_details',
            args: { customer: frm.doc.customer },
            callback: function(r) {
                frm.set_value('customer_name', r.message.name);
            }
        });
    }
},

validate: function(frm) {
    // Validate before save
    if (!frm.doc.customer) {
        frappe.throw('Customer is required');
        return false;
    }
},

before_save: function(frm) {
    // Before save actions
    frm.doc.modified_by_script = 1;
},

after_save: function(frm) {
    // After save actions
    frappe.show_alert('Document saved!');
}

});

// Child table events frappe.ui.form.on('Sales Invoice Item', { qty: function(frm, cdt, cdn) { let row = locals[cdt][cdn]; row.amount = row.qty * row.rate; frm.refresh_field('items'); },

items_add: function(frm, cdt, cdn) {
    // New row added
    let row = locals[cdt][cdn];
    row.warehouse = frm.doc.default_warehouse;
},

items_remove: function(frm) {
    // Row removed - recalculate totals
    calculate_totals(frm);
}

});

Dialogs

// Simple prompt frappe.prompt( {fieldname: 'name', fieldtype: 'Data', label: 'Name', reqd: 1}, function(values) { console.log(values.name); }, 'Enter Name' );

// Multiple fields frappe.prompt([ {fieldname: 'name', fieldtype: 'Data', label: 'Name', reqd: 1}, {fieldname: 'email', fieldtype: 'Data', label: 'Email', options: 'Email'}, {fieldname: 'date', fieldtype: 'Date', label: 'Date', default: frappe.datetime.nowdate()} ], function(values) { console.log(values); }, 'Enter Details', 'Submit');

// Custom dialog let dialog = new frappe.ui.Dialog({ title: 'My Dialog', fields: [ {fieldname: 'customer', fieldtype: 'Link', options: 'Customer', label: 'Customer'}, {fieldname: 'amount', fieldtype: 'Currency', label: 'Amount'} ], primary_action_label: 'Submit', primary_action: function(values) { console.log(values); dialog.hide(); } }); dialog.show();

// Confirmation frappe.confirm( 'Are you sure you want to proceed?', function() { // Yes process_action(); }, function() { // No } );

Utilities

// Messages frappe.msgprint('Hello World'); frappe.msgprint({ title: 'Success', message: 'Operation completed', indicator: 'green' });

frappe.throw('Error message'); // Stops execution

frappe.show_alert('Quick notification', 5); // 5 seconds

// Date/time frappe.datetime.nowdate(); // "2024-01-15" frappe.datetime.now_datetime(); // "2024-01-15 10:30:00" frappe.datetime.add_days('2024-01-15', 7); frappe.datetime.str_to_obj('2024-01-15');

// Format frappe.format(1234.56, {fieldtype: 'Currency'}); frappe.format('2024-01-15', {fieldtype: 'Date'});

// Routing frappe.set_route('Form', 'Customer', 'CUST-001'); frappe.set_route('List', 'Customer'); frappe.set_route('query-report', 'Sales Report');

// Current route let route = frappe.get_route();

REST API

Authentication

Token-based

curl -X GET "https://site.com/api/resource/Customer"
-H "Authorization: token api_key:api_secret"

Session-based (login first)

curl -X POST "https://site.com/api/method/login"
-d "usr=user&pwd=password"

CRUD Operations

List

GET /api/resource/Customer?filters=[["status","=","Active"]]&fields=["name","customer_name"]&limit_page_length=10

Get single

GET /api/resource/Customer/CUST-001

Create

POST /api/resource/Customer Content-Type: application/json {"customer_name": "New Customer", "customer_type": "Company"}

Update

PUT /api/resource/Customer/CUST-001 Content-Type: application/json {"customer_name": "Updated Name"}

Delete

DELETE /api/resource/Customer/CUST-001

Call Methods

Call whitelisted method

POST /api/method/myapp.api.get_customer_details Content-Type: application/json {"customer": "CUST-001"}

JavaScript Fetch

// Using fetch API async function getCustomers() { const response = await fetch('/api/resource/Customer?limit_page_length=10', { headers: { 'Content-Type': 'application/json' } }); const data = await response.json(); return data.data; }

// POST request async function createCustomer(customerData) { const response = await fetch('/api/resource/Customer', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(customerData) }); return response.json(); }

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

client-scripts

No summary provided by upstream source.

Repository SourceNeeds Review
General

bench-commands

No summary provided by upstream source.

Repository SourceNeeds Review
General

server-scripts

No summary provided by upstream source.

Repository SourceNeeds Review
General

frappe-api

No summary provided by upstream source.

Repository SourceNeeds Review