REST v2 Orders API: Need Support for Custom Line Items (Shipping, Tax, Fees, Discounts) - Critical for XML-RPC Migration

The REST v2 /orders endpoint currently requires product_id for all order items, making it impossible to add shipping charges, taxes, fees, or discounts. This is a critical blocker for migrating from XML-RPC to REST API before the 2026 deadline.

With the announcement that XML-RPC will be deprecated and brownouts starting in 2025, we’ve begun migrating to REST v2 API.

However, we’ve discovered that the REST v2 /orders endpoint has severe limitations compared to XML-RPC:

What Works :white_check_mark:

POST/v2/orders{"order_items":[{"product_id":"123","quantity":1}]}

Result: HTTP 201 - Order created successfully

What Fails :cross_mark:

Attempt 1: Custom Line Item with Price

{"order_items":[{"description":"Shipping Charge","price":10.00,"quantity":1}]}

Result: HTTP 400 - "Unrecognized property: price"

Attempt 2: Using product_id = 0

{"order_items":[{"product_id":0,"description":"Sales Tax","quantity":1}]}

Result: HTTP 400 - "product_id"

Attempt 3: Using item_type


{"order_items":[{"description":"Shipping","item_type":"SHIPPING","price":10.00,"quantity":1}]}

Result: HTTP 400 - "Unrecognized property: item_type"

We also tested REST v1 /orders/{orderId}/items with the same results - it also requires a valid product_id.

The XML-RPC addOrderItem method supports product_id = 0 for custom line items:

// Shipping
addOrderItem(invoice_id, 0, 1, 10.00, 1, “Shipping”, “Standard Shipping”)

// Tax
addOrderItem(invoice_id, 0, 2, 2.50, 1, “Sales Tax”, “CA Sales Tax”)

// Discount
addOrderItem(invoice_id, 0, 7, -5.00, 1, “Discount”, “SAVE10 Coupon”)

// Custom Fee
addOrderItem(invoice_id, 0, 13, 3.00, 1, “Processing Fee”, “”)

This flexibility is essential for e-commerce integrations.

We need the REST v2 /orders endpoint to support custom line items without product_id, similar to XML-RPC capabilities:

Supported item_type Values:

  • PRODUCT (default, requires product_id)

  • SHIPPING (custom price, no product_id)

  • TAX (custom price, no product_id)

  • DISCOUNT (negative price, no product_id)

  • FEE or OTHER (custom price, no product_id)

Backward Compatibility:

  • If product_id provided: Use product pricing (current behavior)

  • If product_id omitted/null and item_type specified: Use custom price field

  • If price omitted: Default to 0

Questions for Keap Team

  1. Is there a planned timeline for custom line item support in v2?

  2. Is there an alternative v2 endpoint we should use for e-commerce orders?

  3. Will v1 REST /orders/{id}/items be enhanced to support custom items?

  4. What is the recommended migration path for integrations using addOrderItem with product_id = 0?

@Mark_Joseph, curious question, what is the reason why you are not assigning product ids to the orders?

Personally, I recommend that you do that, so that they can easily be reported on when running reports via the application, or using the API.

The workaround solution would be to query the Products by its Name, and then use the Create endpoint to create the product.

https://developer.infusionsoft.com/docs/restv2/#tag/Products/operation/listProductsUsingGET_1
https://developer.infusionsoft.com/docs/restv2/#tag/Products/operation/createProductUsingPOST_1

Looking at the REST documentation, there is a variation of the Item types between v1 and v2.

Highly unlikely REST v1 will be enhanced, because all the development work is now on REST v2. REST v1 had multiple shortcomings, and was not a suitable replacement for XML-RPC.

@OmarAlmonte will be back in the new year, he will give you an official response to your questions.

@Pav Thanks for the response!

The issue is that shipping, taxes, fees, and discounts don’t have product IDs in a typical e-commerce flow - they’re calculated dynamically at checkout:

  • Shipping: Varies by carrier, weight, destination (USPS Ground 10,FedEx2−Day25, etc.)

  • Taxes: Varies by jurisdiction (CA 7.25%, NY 8.875%, etc.)

  • Fees: Processing fees, handling fees (3.50,5.00, etc.)

  • Discounts: Coupon codes (SAVE10 = -$10.00, etc.)

Creating a Keap product for every possible combination isn’t scalable:

  • 50+ US state tax rates

  • 10+ shipping methods per carrier

  • Unlimited coupon codes

  • Dynamic fees

The XML-RPC addOrderItem() method handles this by accepting product_id = 0 with type codes (1=Shipping, 2=Tax, 7=Discount, 13=Fee). This has worked perfectly for 10+ years across thousands of merchants.

What we need in v2: The same flexibility - either:

  1. Accept product_id = 0 or null for custom items, OR

  2. Support an item_type field that bypasses the product_id requirement

Without this, we’re blocked from migrating 95% of real-world orders to REST v2.

Looking forward to @OmarAlmonte 's guidance in the new year!

@Mark_Joseph Thanks for reporting this. I’ll raise it internally and we’ll share updates as soon as we have them.