commera.sdk is the stable Python API for plugins. Use it instead of Commera's internal modules, which can change in any release. Every read checks the session user's permissions.
| Name | What it does |
|---|---|
commera.sdk.API_VERSION |
The API version this Commera supports, 1 |
commera.sdk.STORE_ORDER_TYPE |
"Shopping Cart", the Order Type of a store order |
commera.sdk.as_plugin_user(app) |
Runs a block as Commera's plugin user |
commera.sdk.orders.get_order |
Reads one order |
commera.sdk.orders.get_orders |
Reads many orders |
commera.sdk.orders.record_shipment |
Records a shipment for an order |
commera.sdk.catalog.get_items |
Reads items with their store price and stock |
commera.sdk.cart.get_cart |
Reads the session shopper's cart |
commera.sdk.cart.set_cart_fields |
Saves your fields on the cart |
commera.sdk.events.CommeraEvent |
The argument of an event handler. See Events |
The return shapes are TypedDicts in commera.sdk.types.
get_order
from commera.sdk import orders
order = orders.get_order("SAL-ORD-2026-00062", extra_fields=["my_app_status"])
| Parameter | Type | Value |
|---|---|---|
sales_order |
str \| int |
The Sales Order name |
extra_fields |
list[str] |
Your own Sales Order fields to read into plugin_fields. Each must start with your app name |
Returns an Order dict:
| Key | Value |
|---|---|
name, customer, customer_name, email, phone |
The order and its customer |
shipping_address |
An Address dict: name, address_title, address_line1, address_line2, city, state, pincode, country, phone. The shipping address, else the billing address. None when there is neither |
placed_on |
The transaction date |
order_type |
The Order Type |
currency, total, net_total, grand_total, rounded_total |
Totals in the order currency |
base_grand_total, base_rounded_total |
Totals in the company currency |
payment_mode |
The checkout payment mode, for example COD |
is_paid, is_cancelled |
Booleans |
status |
The order status that events fire on, for example Shipped |
stage |
{ key, label }, the badge that the dashboard shows |
plugin_fees |
A list of { description, amount }, the fees that plugins added |
items |
A list of lines: line_id (the Sales Order Item name), item_code, title, size, qty, delivered_qty, rate, amount, image |
tags |
The order's tags |
plugin_fields |
The values of extra_fields |
Throws frappe.PermissionError when the user cannot read the order, frappe.DoesNotExistError when it does not exist, and frappe.ValidationError for a field that your plugin does not own.
get_orders
found = orders.get_orders(["SAL-ORD-2026-00062", "SAL-ORD-2026-00063"])
Returns a dict of Order keyed by the order name as a string. An order that the user cannot read, or that does not exist, is left out.
record_shipment
Records a shipment for an order: Commera creates or updates the order's Shipping Request for the AWB. It makes no Delivery Note. The order status, the order_fulfilled and order_delivered events, and the shopper's tracking page follow from it.
from commera.sdk import orders
orders.record_shipment(
"SAL-ORD-2026-00062",
awb="1234567890",
carrier="Delhivery",
tracking_url="https://example.com/track/1234567890",
status="In Transit",
)
| Parameter | Type | Default | Value |
|---|---|---|---|
sales_order |
str \| int |
The Sales Order name | |
awb |
str |
Required, keyword only. The tracking number. Commera finds the Shipping Request by order and AWB | |
provider |
str \| None |
None |
A Shipping Provider Profile name. Leave it empty when a fulfilment partner made the shipment |
carrier |
str \| None |
None |
The carrier name the shopper sees |
status |
str |
"In Transit" |
One of Draft, Ready To Ship, Pickup Scheduled, In Transit, Out For Delivery, Undelivered, RTO, Delivered, Cancelled, Lost |
events |
list[dict] \| None |
None |
Tracking events to add to the shipment |
tracking_url |
str \| None |
None |
A link the shopper can open to track the parcel |
Returns the Shipping Request name.
- A status only moves forward. A lower status than the stored one is ignored. Delivered, Cancelled and Lost are final.
- Call it again with the same AWB to update the status, the tracking events and the
tracking_url. Commera does not make a second shipment. Acarrieron a later call is ignored: the first call sets it. - Without
provider, the shipment has no origin address, because the parcel left the partner's warehouse.
Throws ShippingNotInstalled (from commera.sdk.orders) when bwh_shipping is not installed, frappe.ValidationError for an empty AWB, an unknown status or an unknown provider, and frappe.PermissionError when the user cannot read the order.
get_items
from commera.sdk import catalog
items = catalog.get_items(["TSHIRT-RED-M", "TSHIRT-RED-L"])
Returns a dict of CatalogItem keyed by item code. A code that is not an Item is left out.
| Key | Value |
|---|---|
item_code, title |
The Item |
product |
The template Item, or the item itself when it has no template |
is_listed |
True when a published option on the storefront sells the item |
price |
What a shopper pays. None until the store's price lists are set in Commera Settings |
list_price |
The struck-through price, or None |
currency |
The store currency |
available_qty |
The quantity the store warehouse can sell. For an item that sells without stock, it can be 0 or less. See Gotchas |
Throws frappe.PermissionError when the user cannot read Item.
get_cart and set_cart_fields
get_cart() returns the session shopper's cart, a guest's included, or None when they have no cart. The Cart dict has name, customer, currency, items (item_code, title, qty, rate, amount), total, grand_total and plugin_fields (every Quotation field that an installed Commera plugin owns).
set_cart_fields(values) saves your own Quotation fields on the cart, prices your fees again, and returns the checkout summary: subtotal, shipping, cod_charge, plugin_fees, taxes, discount_amount, rounding_adjustment, total, and the same figures for cash on delivery under cash_on_delivery.
import frappe
from commera.sdk import cart
@frappe.whitelist()
def set_gift_wrap(enabled: bool):
return cart.set_cart_fields({"my_app_gift_wrap": int(enabled)})
set_cart_fields throws frappe.DoesNotExistError when the shopper has no cart, and frappe.ValidationError for a field that your plugin does not own, or when the cart is already paid or a payment for it is in progress.
as_plugin_user
A webhook from a partner arrives as Guest, with no permission to read orders. Run the SDK calls inside as_plugin_user:
import frappe
from commera.sdk import as_plugin_user, orders
@frappe.whitelist(allow_guest=True, methods=["POST"])
def shipment_webhook():
payload = frappe.parse_json(frappe.request.get_data(as_text=True))
# verify the partner's signature here before you trust the payload
with as_plugin_user("my_app"):
orders.record_shipment(payload["order"], awb=payload["awb"], tracking_url=payload.get("tracking_url"))
The plugin user holds every desk role. Verify the request before you enter the block. as_plugin_user throws when the plugin is not installed.