On this page

Task Index — Find the Right Section Fast

How to use this repo without drowning in it: the numbered docs are the deep manual — most are over 1,000 lines. Don't read a whole doc for one task. Find your task below and open only the linked section. If you're an AI assistant: read CLAUDE.md, then this index, then just the sections your task needs.

Every task assumes you already have a token and (for Transaction/Interactive) the UI server URL — see Getting a token below.

Doing, not studying? The recipes cookbook has self-contained copy-and-run pages (complete payload + full script + gotchas) for the most common tasks — start there and fall back to the manual sections for depth.


First call of any session

Task Where
Get a bearer token (v2, credentials in body) 00 § Method 1: User Credentials
Authenticate with a consumer key 00 § Method 2: Consumer Key
Configure a consumer key's API Scope (URL scopes, OData table allow-list) 00 § API Scopes
Get the UI server URL (Transaction/Interactive base) — 307 redirect gotcha 00 § UI Server URL
Token TTL / reuse across APIs 00 § Token Lifetime and Reuse
Detect P21 server version / production flag (undocumented endpoint) 00 § Server Info Endpoint
Fix "not authorized" (P21 user permissions) 00 § P21 Permissions — or, if using a consumer key, its scope may simply exclude the table you asked for; decode the token's aud claim before assuming it's a permission gap
Pick which API to use for a task 01 API Selection Guide (short — read whole)
A write failed — will the other API get through? (usually no) 01 § Interactive Is Not an Escape Hatch

Read data (OData)

Task Where
Query a table or view 02 § Query Parameters
Filter syntax, operators, string functions 02 § Filter Expressions
Only active rows — row_status_flag or delete_flag, depending on the table 02 § Active Record Filter — soft-deleted rows keep their old values and dominate some tables
Compare two columns in a $filter (total_amount gt amount_paid) 02 § The right-hand side is always a literal — 404 on typed columns, silently zero rows on strings
Long or chain 404s with an HTML page, or you need hundreds of ids in one filter 02 § Long filters and POST /$query — 8,192-character query string, 799-term flat chain; POST {collection}/$query with a text/plain body
in (...) or $apply (aggregate, groupby) returns rows but ignores the clause 02 § What the service supports — both are accepted and silently ignored
Money or quantity sums are off by a fraction 02 § Decimals arrive as JSON numbers — parse as decimal, or send IEEE754Compatible=true
Order lines for open orders only (lines carry no completed / approved / projected_order) 02 § Order lines carry no header status
Age open AR / build a receivables aging recipes/ar-aging — runnable, pages invoice_hdr, buckets on each invoice's own net_due_date
Age open AR / "how late is this invoice?" 02 § customer.terms_id is the default for the next document — age on the invoice's own net_due_date
Filter 404s on a value that looks right (Edm.Decimal vs Edm.String) 02 § Active Record Filter — many *_id columns are numeric; don't quote them
Company column is company_id on some tables, company_no on others 02 § Company Scoping
Read a customer/supplier/ship-to mailing or physical address over OData (address table) 02 § Common Tables — columns keep the mail_/phys_ prefix (mail_address1, not address1); 404 without it
Read P21 user accounts (users) — 401, or 200 with an empty value 02 § One table is withheld from every token: users — withheld from consumer keys and password grants by design; no OData workaround
Does an OData read immediately after a Transaction write ever return stale data? 02 § Read-after-write consistency — 125/125 clean on the table: surface, light load; view: untested
Traverse relationships (no joins — chain by _uid) 02 § No Joins
Page through large result sets (no nextLink) 02 § Pagination Helper · 02 § Page Size Guidance
Date filters (now() is unsupported) 02 § now() Not Supported
New table/column missing from OData 02 § OData Schema Refresh
Empty-bodied 404 on a table you know exists 02 § The table/view split — views live on /view/, base tables on /table/; asking the wrong one 404s exactly like a missing object
Read a view (p21_view_*), or a user-defined table (*_ud, site-custom) 02 § The table/view split — views on /view/; *_ud are ordinary base tables on /table/
Table reads fine but is empty/inert (undeployed feature, e.g. zip→rep) 02 § Undeployed / Unlicensed Windows
Denormalized, search-friendly views (p21_view_es_*: customer, item, order, invoice, etc.) 02 § Enterprise/Global Search Views
Value inventory adjustments — inv_adj_line.cost is 0 02 § inv_adj_line.cost is 0 — use inv_tran.unit_cost_amt; net both directions
Show the label of a user-defined dropdown value 02 § User-defined dropdown labels — extensibility_dropdown_value, not code_p21
A column you're sure exists 404s (qty_completed, line_number, prod_order_hdr.location_id) 02 § Column names that trip queries
Kit / assembly margin looks negative, or kit cost is counted twice 02 § Kit and assembly lines — parent commission_cost is pre-rebate; invoice_line_uid_parent ≠ 0 marks component lines

Create / update records (Transaction API)

Task Where
Payload anatomy (TransactionSet / DataElements / Edits) 03 § Request Structure
Payload rejected / values not landing (shape & type mistakes) 03 § Payload Anatomy
HTTP 200 with Summary 0/0/0 and nothing written 03 § Common mistakes — the body is wrapped in "TransactionSet" or starts at the transaction
Edit the header of a completed PO (Save is not enabled.) 03 § Editing a Completed PO
Clear a field, or write NULL 03 § Edit fields — a blank stores NULL, an empty string or nothing, depending on the field; read it back
Add a price book to a pricing library at a position 03 § StrategicPricingLibrary Service
Validate a payload offline before posting (JSON or XML) scripts/validate_payload.py · 03 § Payload Anatomy
Copy-ready payload files (JSON and XML, validator-verified) examples/payloads/
Send/receive XML instead of JSON 03 § XML Payloads
Get a service's schema, template, defaults 03 § Endpoints · committed full-field JSON in definitions/
Update an existing record (Status "New" + keys; "Existing" is broken) 03 § Updating an Existing Contract
Insert new keyed rows (upsert) + one-tx-per-POST rule 03 § Upsert Semantics
Two lines came back as one — same item twice, only the last quantity landed 03 § Keys — Row Identity and the Collapse Trap
Pick the right Keys for an element (and what over-keying breaks) 03 § Choosing a key · 03 § What the definition already tells you
Child rows all attached to the last parent (extended info, lots, breaks) 03 § The general rule: repeat the element pair
Read one record whole / clone an existing record 03 § Reading One Record
Read several records in one /transaction/get call (no field/element subsetting exists) 03 § Reading several records in one call
Failed: 1 but part of my batch landed 03 § What Failed actually guarantees — a Transaction is atomic; Transactions in one POST are not
A failed create still left an order behind / an order number was skipped 03 § A failed create leaves rows behind — soft-deleted header and lines, number consumed; filter delete_flag = 'N'
Append many lines to a saved order · cancel an order · release a Hold · Ambiguous data detected / 'X' has been deleted 03 § Order Service — Line Appends, Cancels, Holds, and Item Lookup · runnable: order_append_hold_cancel.py / OrderAppendHoldCancel.cs
Order with hundreds of lines is slow — split it 09 § Large Sales Orders: Split at About 100 Lines
Create a purchase order 03 § PurchaseOrder Service
Create a direct-ship PO from a sales order (drive a wizard) 04 § Driving an In-Window Wizard — needs a Buyer ID; commits at cb_next
Change the salesrep on an order or quote 03 § Order Service — Reassigning the Salesrep — TP_SALESREPS.tp_salesreps; oe_hdr has no salesrep column
Transaction Failed with no reason on the transaction 03 § Failure detail is in the top-level Messages
"may currently be edited by USER" — write refused 03 § oe_hdr.completed = 'T' — pre-screen WHERE completed <> 'T'; usually an abandoned lock
Telling quotes from live orders 02 § Quotes are projected_order = 'Y' — quote_type is NULL everywhere
What a PO type letter means (B is buyer-keyed, not backorder) · where a PO came from (source_type) · how a deleted PO looks 03 § Purchase Order Types
"When did the supplier say this would ship?" 02 § po_line.supplier_ship_date — not a promise on direct-ship POs; use date_due
Peg a PO line to the sales order it was bought for (oe_line_po) 02 § oe_line_po holds stale links — join on both key pairs and filter delete_flag; a deleted PO leaves its sales lines open with nothing on order
Convert an existing order line to direct ship — docs said it was refused recipe: order-line-to-direct-ship · 04 § Changing a saved line to direct ship — the gate is allocated stock, not the saved state: set TP_EXTDINFO.extd_info.allocated_qty = 0, then disposition = D; /transaction also needs po_cost
Confirm a direct ship (DirectShipConfirmation) 04 § The Interactive path works (runnable: direct_ship_confirmation.py) · 04 § The Transaction API path works on 26.1.5950.0 — one POST keyed by po_no · 04 § DirectShipConfirmation writes its ship date down — overwrites supplier_ship_date on every line; checkboxes take ON/OFF
Receive a PO / receipt won't post (bin errors) 03 § PurchaseOrderReceipt Service
Vouch a receipt against a vendor invoice 03 § ConvertPOToVoucher Service
Column is disabled for my service account but not for a person 03 § Column is disabled Can Mean "Disabled For You" — role/DynaChange-scoped; test with the account that will run it
Is the definition's Required flag trustworthy? 03 § What Required actually means — no, wrong in both directions
Sequence contains no matching element / Invalid column name on a keyed write 03 § Choosing a key — every Keys field must be a real column and be sent in Edits
Write a note on an order (header/line) 04 § Sales Order Notepad Writes · 04 § PurchaseOrder Notepad Writes — Interactive only; /transaction refuses (why)
Write a note on a production order (note_type_cd 2758) 04 § Production Order Notes — Interactive only; /transaction reports success and writes nothing (why)
Write an item / customer / supplier note 03 § Commands Endpoint — one stateless POST · or 04 § Standalone Notepad Windows, where the mandatory area picker is cb_selectall via /tools
Call a commands-only service (notepads, reverse payment, slab adjustment) 03 § Commands Endpoint — request shape and Action codes
Get an async callback instead of polling 03 § Callbacks instead of polling
Fetch one record by key over OData 02 § The other OData surface — /data/erp/views/v1/{view}('key')
Consumer key 401s on a table you just granted it 00 § The OData allow-list is baked into the token — scope is fixed at issue time and the tokens last ~20 years; mint a new one. users never works, whatever the scope (02)
Which OData version / what's supported 02 § Protocol version · 02 § What the service supports — v4; no server-driven paging
Does my server have endpoint X? 05 § Discovering what your tenant actually exposes — apiref.aspx + per-family /help
Valid P21 login rejected by the middleware admin site 00 § Application Security settings — needs Access to SOA Admin Page
Attribute API writes to a real user, not the service account 00 § Attributing writes to a real user
Who can read a consumer key's value (DynaChange rules) 00 § Method 2: Consumer Key — RuleState.ConsumerKey exposes it to any rule author
Update a specific order line deterministically (line handles) 03 § Design for updates: assign your own line handles · recipe: update-order-lines
You cannot retrieve an RMA from the Order Entry/Front Counter window 03 § RMA Service — use the RMA service; route on oe_hdr.rma_flag
A tool is missing from GET /v2/tools on a multi-tab window 04 § Sales Order Notepad Writes — tool lists are tab-scoped and accumulate; select the tab first
Which discovery endpoint — definition vs defaults vs basics 03 § Endpoints
Write through disabled columns/tabs (IgnoreDisabled) 03 § IgnoreDisabled — not a universal unlock; it can report success and write nothing
Contract break tiers refuse to save / "Tab page is disabled" 03 § VALUES Writes Are Refused on 26.1 · 14 § entry 8
Field order silently changing values 03 § Field Order Matters
Labels vs code_no (UseCodeValues, code_p21) 03 § UseCodeValues
Check success properly (HTTP 200 lies; per-tx pass/fail) 03 § Response Format · 06 § Transaction API Errors
Read a record back / verify a write 03 § Endpoints — /transaction/get
Long-running / async transactions (no cancel path once queued; status 2 ≠ success — outcome is a JSON string inside Messages) 03 § Async Operations
DynaChange rules & popup suppression for the API user 03 § DynaChange and Popup Handling
Run a stored procedure via API 03 § Stored Procedure Executor

By record type

Task Recipe Manual
Create a sales order + gotchas (source_loc_id, dates, DynaChange) create-sales-order 03 § Create Order · 03 § Order Service Gotchas
Order with an assembly line (explode / spawn prod order) order-with-assembly 04 § Sales Order Entry with Assembly Lines
Job contract: create, lines, breaks — 03 § JobContractPricing Service
Job contract: update / add lines / commission costs update-contract-lines 03 § Updating an Existing Contract · 03 § Upsert Semantics · 03 § Commission Costs
Job contract: bin quantities edit-contract-bins 03 § Editing Bin Quantities (Interactive fallback: 04 § Tab Unlock Sequences)
Job contract: attach a ship-to (pricing follows the ship-to grid, not the header) — 03 § Attaching a ship-to · runnable: contract_shipto_line_no.py / ContractShipToLineNo.cs
Job contract: update one of two lines with the same item_id (select by line_no; no end_date, no header re-save) — 03 § Commission Costs · 03 § Updating an Existing Contract · runnable: contract_shipto_line_no.py update-line
Job contract: edit an expired contract / "You may not change the end date of this record" update-contract-lines 03 § Updating an Existing Contract — omit end_date unless you are changing it
Job contract: how cost settings reach the order and invoice (binding at entry, commission Value vs Order vs Source, rebate prerequisites, duplicate item_id lines) rebate-assembly-program 03 § How Contract Costs Reach the Order and the Invoice
Rebates on assembled parents — production orders (linked or build-to-stock) and kits; which vendor gets the rebate (vendor_rebate.vendor_id = oe_line.supplier_id) rebate-assembly-program 03 § Rebates on assembled parents
A fixed per-unit rebate on a contract line (other cost Source / Average Cost / Difference, positive value) rebate-assembly-program 03 § A fixed per-unit rebate
GL entries of a rebated invoice (Sales Journal at moving average, Rebate Journal pair) — 03 § The GL flow of a contract rebate
Assembly / BOM definition — create (Transaction on a plain item, Interactive when the item is already a component) and edit new-assembled-part 03 § Part + Assembly Creation Workflow · 03 § Assembly Service · runnable: assembly_create_edit.py / AssemblyCreateEdit.cs
Assembly create: production_order_processing came back ON / Column is disabled: item_desc — 03 § Defaults and Disabled Fields on Create
Item: primary bin / primary supplier at a location set-primary-bin-supplier 03 § Item Service
Create a brand-new item — Item service alone 500s with ...tabpage: TABPAGE_2 or A Default Sales Unit... Must Each Be Specified — 03 § Item Service Gotchas — use 11 § Minimum Create Payload instead
Inventory REST create 500s — what does the error actually mean, is anything left behind — 11 § An incomplete create payload 500s — message names the missing block; nothing persists on failure
Soft-delete an item (inv_mast.delete_flag) idempotently — and why a second write of any kind then fails — 03 § Item Service Gotchas — a deleted item blocks every further Item-service write, not just a repeated delete; check delete_flag over OData first
Item: add a supplier to a location's list (the flip's prerequisite — both keys + IgnoreDisabled) set-primary-bin-supplier 03 § Adding a Location Supplier Row
Item: enable bin tracking at a location (track_bins, and the bin it auto-assigns) — 03 § Enabling Bin Tracking
Item: change a location's product group without losing its GL / revenue / COS accounts — 03 § Changing a Location's Product Group Re-Syncs Its GL Accounts — the move resets the accounts to the target group's defaults; snapshot before, restore after
Item: set the header default product group (inv_mast.default_product_group) — 03 § Item Service Gotchas · 11 § Known Limitations — no API write path; the location product group is writable
Merge two items or two customers (m_itemmerge / m_customermerge) — and what history moves, changes, or is lost — 03 § Item Merge and Customer Merge — customer merge reports Failed: 1 when it succeeds; merged item IDs resolve through alternate codes · runnable: item_customer_merge.py / ItemCustomerMerge.cs
Create warehouse bins create-bins 03 § BinLocation Service
Lock, unlock or delete bins (a skipped delete reports no error — read back through the p21_view_bin OData view) — 03 § Locking, Unlocking, and Deleting Bins · runnable: bin_lock_delete.py / BinLockDelete.cs
Create a new warehouse/location — a specific id is refused, a blank one false-succeeds at location_id=0 — 03 § Location Service — the fix is Keys: [] with no id at all; P21 assigns a real number
Location: update or soft-delete an existing warehouse — company_id becomes Column is disabled after create — 03 § Location Service — Updating
Sales price pages (codes, breaks, field order) — 08 SalesPricePage Codes · 08 § Transaction API Alternative
Purchase-side pricing pages (supplier / item / discount group) — 08 § Purchase-Side Pricing Services
Create a sales price page through the Transaction API + link it to a price book (USED BY cannot link) — 08 § Creating a Page Through the Transaction API · runnable: sales_price_page_create_link.py
Edit a supplier/item purchase page in place (exact keys, full field set, labels not codes) — 08 § Editing a Supplier/Item Purchase Page · runnable: purchase_pricing_page_edit.py
Break fields named differently per service (calculation_value1 vs value1) — 08 § Cross-Service Break-Field Names
What a stored price_page_type_cd means (212 = Item) — and why a code from one column's table can't decode another — 08 § Price Page Type
Set a carrier tracking number on a pick ticket (and why not after invoicing) — 03 § Shipping Service — Carrier Tracking Number
Delete a pick ticket — Record specified was not found on an orphaned ticket — 03 § Shipping Service — Deleting a Pick Ticket — tickets left on completed orders cannot be reached by the API or the client
Reassign a salesrep (customer + ship-to) reassign-salesrep 03 § Payload Anatomy
Turn on Job/Contract Pricing for a customer — Column is disabled: job_pricing (use_vendor_contracts_flag first) — 03 § Customer Service — Turning On Job/Contract Pricing
Remove a rep from a customer's grid (no delete_flag — it's row_status_flag: "Delete") reassign-salesrep 03 § Customer Service — Removing a Salesrep Grid Row
A grid row looks undeletable — no delete_flag in the definition — 03 § Read ValidValues before assuming a grid can't delete
Edit a salesrep's name/email (contact_id key; email on TABPAGE_2) — 03 § Salesrep Service
Update a supplier's contact details (central email/phone live on Address, not Supplier) update-supplier-contact 03 § Salesrep Service
Modify an existing sales order (edit a line in place, add a line) update-order-lines 03 § Design for updates: line handles
Item Defaults per location (required before location-appends on fresh locations) — 03 § ItemDefaults Service
Create bin zones (fresh-location prereq for bins) — 03 § PutawayZone / PickZone Services
Create a customer (salesrep_id + default_branch gotchas, no zip→rep cascade) create-customer 03 § Common Services
Create a ship-to on an existing customer (element map, UseCodeValues: true, inherited rep) create-ship-to 03 § ShipTo Service — Creating a Ship-To
Create a requisition PO (po_type 'R'; disabled po_hdr_po_type; vendor vs supplier) create-requisition-po 03 § Purchase Order Types
GL dimensions via API (voucher services carry them; POs don't) — 03 § GL Dimensions in the API
Create a vendor (and its auto-created supplier; ID rule; rebate tracking) rebate-assembly-program 03 § Vendor Service · runnable: vendor_create.py / VendorCreate.cs
Change an item's average cost / write residual cost down (InventoryCostEdit) inventory-cost-edit 03 § InventoryCostEdit Service
Dispose of zero-value stock on a $0 order dispose-zero-value-stock 03 § Order Service — Line Appends
Stock PO → receipt → voucher, and drop ship end to end purchase-receive-vouch 03 § PurchaseOrder · 04 § Driving an In-Window Wizard
Sales order → pick ticket → invoice sales-order-to-invoice 03 § Create Order · 12 § Shipping and Invoicing
Customers / vendors / contacts / addresses (simple CRUD) — 05 § CRUD Operations
Read/create sales orders via REST (/api/sales/orders) — 05 § Other REST Endpoint Families · 05 § Creating an Order — trailing slash required; lines nest under Lines.list
Filter /api/sales/orders ($query) or get an order's lines over REST — 05 § /api/sales/orders — PascalCase names (OrderNo); extendedproperties=Lines
REST-family read returns POLines / Lines as null — 15 § Child collections — add extendedproperties
Price many items through /api/ecommerce (XBG GetItemPrice) — 05 § api/ecommerce — StoreName is the company ID; unknown items still return Result 0
Price or check availability for an item ID containing / — 11 § URL Encoding — v2/parts/v2/price/{id} with %2F, v2/parts/availability?itemId=, or parts/?$query=ItemId eq '{id}' to read the part
Write Clippership tracking rows, or count rows on /data/erp/views/v1 — 02 § /data/manifest/v1 · 02 § Documented limitations ($inlinecount=allpages)
Inventory items: read / create / update locations — 11 § Reading Items · 11 § Minimum Create Payload · 11 § Updating Existing Location Fields
Update a supplier's cost or list price over REST (Suppliers.list[].Cost / ListPrice; restamps every inv_loc) — 11 § Updating a Supplier's Cost · runnable (ListPrice + Stockable): inventory_update_list_price_stockable.py
Clone an existing item under a new ID (REST GET → strip → POST) — 11 § Cloning an Existing Item
REST create or location append fails Required value missing for Revenue Account · which DivisionId to send — 11 § GL accounts when the location has no defaults · 11 § DivisionId is often the supplier ID
Append locations at scale (supplier-x-loc primary, GL requireds, kit Buy, OP/OQ, retries, PrimaryBin, discount groups from location defaults) — 11 § Location-Append & Update Gotchas
Customer-specific price + availability lookup — 11 § Pricing Endpoints
Batch price + availability lookup (multiple items in one call, JSON or XML) — 11 § Batch Pricing
User-defined tables (UDT) rows — 13 § Insert · 13 § Update · 13 § Delete — update/delete select a row by primary key with {"rowuid": N}; a name/value condition is a 400 or a silent no-op
UDT delete "succeeds" but nothing is deleted — 06 § [0] rows deleted · 14 § entry 7
Bulk-load a UDT from CSV (2026.1+) — 13 § Bulk Data API — CSV upload; headerless file silently inserts nothing

Drive a window (Interactive API)

Task Where
Session → window → change → save lifecycle 04 § Session Lifecycle
v2 payload shapes (save body is the bare GUID, etc.) 04 § v1 vs v2 API Differences
Find field / tab / datawindow names 04 § Finding Field Names · 04 § Window Discovery
Read a window's SQL — the datawindow's full SELECT, its column → table.column map, and one field's table, datatype, and update table 04 § P21 SQL Information · recipe: window-sql-information — run m_sqlinformation with POST /v2/tools; the SELECT comes back only from POST ui/full/v2/window/page {"PageName": "SQL"} on the dialog, as TextBoxes[].Text
Which table does this field write? — an API field name that is not a database column (sales_loc_id, buyer_id) 16 Window Field-to-Table Maps — 228 datawindows in 7 windows, each field resolved to table.column; files in definitions/window-maps/
An action works in the client but not the API — capture the web client's request and replay it 04 § Browser DevTools — the web client calls ui/full, not /api/ui/interactive; worked example: selecting one row (ui/full/v2/data/select)
Open a window (use ServiceName — Name/Title can 400) · map window→service 04 § Open Window · 04 § Window→Service Discovery
The window has no service name (frame_menu.service_name NULL) — drive it by menu class instead 04 § The ui/full Surface
See which windows an Interactive session holds, keep it alive, or end one by ID 04 § Session Management — sessions/state, sessions/ping, api/ui/admin/session/{id}
v1 Interactive change returns 404 or changes nothing 04 § Data Operations (v1) — use v2; the v1 path takes only the v2 body
Create a contact on an existing customer's address 03 § Contact Service — send address_id
"Cannot open window ** ** because is not available" — the name came back blank 04 § Open Window — blank means the ServiceName never resolved
Handle popups / response windows (Status 3, windowopened) 04 § Response Windows · 04 § Response Window Types
Answer a rule-callback dialog ("Item Issues Detected") 04 § Worked Example — but fix the data first: 03 § Root Cause and Data Fix
Enable, disable or re-scope a DynaChange business rule through the API 04 § Managing Business Rules Through the DynaChange Organizer — the dc.organizer.rule tool on any open window · runnable: dynachange_rule_toggle.py
Interactive order saved as a quote / disposition looks disabled / wizard made an RFQ · build a direct-ship PO 04 § Set quote to OFF first · runnable: order_entry_quote_off.py
Create an item in the Item window (unit flags, one location per session) 04 § Creating an Item in the Item Window — Units of Measure grid can be locked (Column is disabled: unit_id) by a web-client screen version assigned to your role — cause, fix and check query; or use the Inventory REST create
Attach a document to an item, assembly or kit (Document Links) — Transaction API says Column is disabled: link_name recipe: item-document-links — upload with the file handler, add through the Item window's m_addlink dialog (one display area at a time via ui/full/v2/data/select + cb_select, or all with cb_selectall), save · 04 § Adding a Document Link in the Item Window
Add a price library to a customer · library order (sequence_number) 04 § Customer Window: Adding a Price Library — edit order decides the sequence · runnable: customer_price_library.py
Answer a w_message dialog — it's fully controllable, not just auto-answered 04 § Worked Example: w_message
Fill fields in a popup (TabName: null) 04 § Response Window Handling (Tabless)
Buttons / tools (?windowId=, not ?id=) 04 § Running Tools
Unlock a disabled tab 04 § Tab Unlock Sequences
Row selection traps (sync bug, detail-form rebind, row 0) 04 § Known Issues and Workarounds
Key field silently swallowing later edits 04 § Key Fields Commit the Cursor
Verify a save actually persisted 04 § Verifying Writes
PO notepad notes (header vs line) 04 § PurchaseOrder Notepad Writes
Bulk/batch interactive work (session reuse, error recovery) 09 Batch Processing Patterns
Intermittent "Unexpected Response Window" in production 07 Session Pool Troubleshooting

Production & manufacturing

Task Where
Service catalog & schemas (ProductionOrder, TimeEntry, …) 12 § Available Services
Assembly behavior flags (prod-order vs kit vs build-to-stock) 12 § Assembly Behavior Flags
Link an existing production order to a sales-order line — docs said the API could not recipe: link-production-order · 12 § Production Order Gotchas — Interactive: the grid's right-click tool m_retrieveotheropentransactions, tick assigned, save; the hidden retrieve_open_transactions column is a decoy
Full runbook: create → print → confirm → complete → ship recipe: production-order-runbook · 12 § Production Order Lifecycle
Pick ticket won't generate (make loc vs stock loc) · sales order: m_picktickets returns HTTP 200 [] 12 § Printing the Pick Ticket · 03 § m_picktickets example · sales order: recipe § Eligibility traps — omitted date ranges take past-dated defaults; an under-allocated kit skips the whole order
Confirm a pick (shell-confirm trap — use Interactive) 12 § Confirming the Pick
Complete / production receipt (+ per-component cost override) 12 § Completing the Production Order
Record labor hours recipe: record-labor-time · 12 § Recording Labor Hours · 12 § Time Entry Against a Production Order
Ship + invoice 12 § Shipping and Invoicing
Inventory write-off / adjustment recipe: inventory-adjustment · 12 § Inventory Adjustment
Why COGS doesn't match the receipt 12 § Cost Model
Report labor actuals — who did the work (service_technician_uid, not created_by), no work-performed date 12 § Reading Labor Actuals
Make vs parts location, UD fields hidden from the API role, cancel a pick ticket, qty_to_complete pre-fill, reprints, linking an existing order to a sales line 12 § Production Order Gotchas (Field-Verified)
New assembled part end to end (item → BOM → contract line → first production order) recipe: new-assembled-part

Documents & reports (PDF)

Task Where
Generate any m_* report as PDF recipe: generate-pick-ticket-pdf · 03 § PDF Report Generation
Invoice PDF (m_invoices) returns an empty HTTP 500 03 § m_invoices needs the API print flag
Print or reprint a PO PDF — empty 500 on every attempt 03 § reprint_flag must match the PO's po_hdr.printed — read printed over OData and send it; never hardcode Y
Discover callable report names (hidden from /services) 03 § PDF Report Generation (Discovery note — includes the right-click SQL Help path)
Empty HTTP 500 from pdfreport on a Crystal report window (TABPAGE_1.tp_1_dw_1 vs CRITERIA.criteria) 03 § The DataElement name comes from the definition
Report returns nothing / runs forever / works for one user only 03 § Report windows are still windows — permissions, DynaChange date caps, cancelling the request does not stop the run
Production pick ticket at a specific location 03 § m_picktickets example
Generate a sales-order pick ticket with m_picktickets — HTTP 200 [], no ticket recipe § Sales-order pick ticket — "Sales Order" with UseCodeValues: false, all three date ranges sent wide, read pick_ticket_no from oe_pick_ticket · § Eligibility traps
Reprint a direct-ship pick ticket — m_reprintpicktickets returned HTTP 200 [] for every direct-ship ticket tested recipe § Direct-ship pick tickets do not reprint — known limitation, most likely a report-side exclusion; no API workaround found
PDFs from print flags on a normal transaction 03 § PDFs from the /transaction endpoint
Merge several report PDFs — barcodes print as text 03 § Merging Several Report PDFs into One File — rename the font-subset tags
Put an assembly's drawing on its pick ticket · does an API pick-ticket PDF include linked documents? · a linked document never prints recipe: item-document-links — display area 3453 Sales Order Pick Ticket · § Printing the document with a form — the link must be Outside Use and the location must send outside-use documents to print (ship-to for the packing list); the PDF is the form alone, and the files come back as DocumentAssociations / filerequested jobs

When something breaks

Task Where
Upgrading P21? What breaks between versions 14 Breaking Changes — registry re-run unchanged on 26.1.5950.0; 2026.1 (sequential fail-fast batched changes, silent-false-success loads, IgnoreDisabled, bad-DatawindowName poison) · resolved in 5940.0 (Accept-header 500, ghost sessions) · 25.2 (DatawindowName)
Empty HTTP 500, no body, on an interactive call 14 § entry 9 — a bad DatawindowName on the previous request; not the Accept header on current builds
What user-defined fields exist in this P21? 15 § extensibility/userdefinedfields — every UDF with type metadata, grouped by table; {tableId} is the *_ud name, not the base table
Read a whole GL journal entry in one call 15 § accounting/gl — GET /api/accounting/gl/{transactionNumber} returns every line, balanced; Source walks back to the originating document
Create or update a CRM task / activity 15 § sales/tasks — verified round trip; "Customer ID is required" means LinkId
A REST family's list route hangs or returns tens of MB 15 § The bare collection GET is an unbounded full-table dump — no paging, and $top is silently ignored; key off OData instead
Post a balanced GL entry over REST 15 § accounting/gl § Posting a journal entry — POST /api/accounting/gl/ takes an array of lines; an unbalanced batch is refused server-side with "Records do not balance"
Create a PO over REST and the price comes back 0.00 15 § purchasing/purchaseorders § Creating a PO — UnitPrice is not honored on create, PriceEdit: "N" routes it through pricing lookup instead; use the Transaction API PurchaseOrder service when the price must be exact
PO create fails Buyer ID... Invalid buyer ID / an unmatched Sales/Production/PO Intersection 15 § purchasing/purchaseorders § Creating a PO — BuyerId empty is the real cause of both messages; the create is built on P21's Import/Export engine, hence the escaped XML error body
createWmsAdjustment fails Bin is required or can't find the adjustment reason 15 § inventory/inventoryadjustments § createWmsAdjustment — binCd is mandatory on a bin-tracked location; reason must name a currently-active reason record, not a historical one
GET /odataservice/odata/table/bin (or /view/bin) 404s with an HTML page, not JSON 02 § One object name is unreachable regardless of surface: bin — likely an IIS routing collision with the reserved bin/ folder name; read inv_loc.primary_bin or bin_ud instead
Upload/download/delete a real file over REST 15 § filehandler — full round trip verified; this is a real network file share, not a sandbox
Read the middleware's build/config without the serverinfo XML trap 15 § environment/systems — JSON directly; no /ping on this family, and needs a trailing slash in C#
Move stock bin-to-bin without changing on-hand quantity 15 § inventorymovement — Y/N not booleans, toBin must already be a real association, "success" doesn't guarantee a nonzero move
Stage a cycle count without touching live on-hand 15 § externalcounts — ItemId must be repeated on the bin sub-record, not just the line
Resolve a scan term / barcode / customer part number to an item 15 § partscan — Source names which identifier matched
Set a customer's invoice/RMA/packing-list report template 15 § customerformtemplates — PUT is not a blind upsert; a null uid against an existing row fails "data already exists"
A "service order" REST family that looks like it should be separate from Order Entry 15 § service/serviceorders — it resolves against any oe_hdr.order_no; the family is a view, not a distinct object
sales/opportunities / consignmentusageorders / exchangerates create fails with a confusing error 15 §§ each family — check the tenant's own lookup tables (opportunity status/stage/type/step, a consignment contract, a second currency) before assuming the API is broken
Which REST endpoints/families does my tenant actually have? 05 § Discovering what your tenant actually exposes — /docs/apiref.aspx lists every family (takes a bearer token); confirm one with /help, never /ping. Plus /api/v2/services (Transaction) and the OData service document
Token call returns HTTP 500 Unable to generate client token. 06 § Token Endpoint Errors — the consumer key is not registered on that tenant; read InnerException, not ErrorMessage. Common after a test-tenant refresh from production (00)
Status: "Existing" / "Update" rejected on a transaction 03 § Status: "New" is the only value — one-member enum; 400 on 5940.0 and later, 500 on older builds
Which .NET runtime do P21 business rules need? 14 § The middleware runtime — both .NET and .NET Framework, for now
Which middleware build am I on? 14 § Reading the middleware version — no version endpoint; it rides the session-create response
Error catalog by API 06 Error Handling (per-API sections)
Write refused for being too long / how long is a field? 06 § Field Length Limits — the API exposes no lengths; measured values + how to measure safely
Quick symptom → cause table 06 § Common Issues Quick Reference
Invalid column name: {field} — is the capability really missing? 06 § Common Transaction Errors — sometimes the sibling field does the job; check ValidValues
Invalid {field} value: 700 on an enum 06 § Common Transaction Errors — send the label, not the code_p21 integer
OData 404 saying Edm.Decimal / Edm.String 06 § Incompatible Operand Types — numeric key column, drop the quotes
Auth failures 06 § Authentication Errors
401 right after a token call that worked (Authorization header was not present) 06 § 401 Authorization header was not present — a 307 stripped the header; send the trailing-slash router URL
Intermittent interactive failures under load 07 Session Pool Troubleshooting
may currently be edited by <your API user> · Transaction fails while an Interactive session is open · order stuck after a crash 06 § Locks and orphaned sessions
What changed in these docs recently 10 Changelog

Doc inventory (what each file is)

Doc Scope Size (line counts as of 2026-10-10)
00-Authentication Tokens (v2/consumer key), permissions, UI server URL large (~1,500 lines)
01-API-Selection-Guide Which API for which job small (~400 lines) — read whole
02-OData-API Read-only queries large (~1,900 lines)
03-Transaction-API Stateless create/update + service reference + PDF reports very large (~5,700 lines) — use anchors
04-Interactive-API Stateful window driving, popups, traps very large (~4,300 lines) — use anchors
05-Entity-API REST CRUD on 4 entities very large (~4,700 lines) — use anchors
06-Error-Handling Errors across all APIs large (~1,400 lines)
07-Session-Pool-Troubleshooting One deep-dive: session pool contamination small (~500 lines) — single topic, read whole
08-SalesPricePage-Codes SalesPricePage field codes/order very large (~2,800 lines) — single service, use anchors
09-Batch-Processing-Patterns Interactive bulk patterns + async client very large (~5,400 lines) — use anchors
10-Changelog Doc change history medium (~800 lines) — newest first
11-Inventory-REST-API /api/inventory/parts read/append/update very large (~2,700 lines) — use anchors
12-Production-Labor-API Production services + end-to-end lifecycle large (~1,100 lines)
13-UDT-Service-API User-defined table CRUD large (~1,800 lines)
14-Breaking-Changes P21 version breaking-change registry (check before upgrading) small (~500 lines) — read whole
15-Other-REST-Families Sixteen more REST families: UDF metadata, GL, CRM tasks/opportunities/consignment orders, PO headers, inventory (adjustments/movement/counts/scan/serial info), file storage, system info, customer form templates, service orders, exchange rates large (~1,100 lines)
definitions/ Full-field service definition JSONs (every DataElement, field, key, label + payload template) load one file per service