cXML
Integrate PrintNow with procurement and Print MIS systems using the cXML protocol for punchout sessions and order submission.
The cXML endpoint enables integration between PrintNow and external procurement systems (e-procurement platforms, Print MIS systems like Presswise, OneFlow, and SiteFlow) using the industry-standard cXML protocol. Unlike the REST API endpoints, cXML uses XML-based request/response envelopes with their own authentication mechanism.
Endpoint
| Method | Endpoint | Content Type | Description |
|---|---|---|---|
POST | /cxml | application/xml | Handle cXML requests (profile, punchout, orders) |
Note that the cXML endpoint lives at /cxml, not under the /api/v2/ prefix used by the REST API.
Authentication
cXML requests do not use the HTTP Basic Auth header. Instead, credentials are embedded in the cXML envelope's <Header> element:
<Header>
<From>
<Credential domain="DUNS">
<Identity>YOUR_STOREFRONT_PUNCHOUT_ID</Identity>
</Credential>
</From>
<To>
<Credential domain="DUNS">
<Identity>157519294</Identity>
</Credential>
</To>
<Sender>
<Credential domain="api.printnow.com">
<Identity>YOUR_API_TOKEN</Identity>
<SharedSecret>YOUR_API_KEY</SharedSecret>
</Credential>
</Sender>
</Header>| Element | Description |
|---|---|
<From> | Identifies the requesting storefront. The credential's domain and Identity must match a storefront's Punchout ID Type and Punchout ID configured in the admin. |
<To> | Must contain PrintNow's DUNS number: 157519294. |
<Sender> | Contains your API token (as Identity) and API key (as SharedSecret) with domain api.printnow.com. These are the same credentials used for REST API Basic Auth. |
Supported Request Types
The cXML endpoint handles three request types within the cXML envelope:
| Request Type | Response Type | Description |
|---|---|---|
ProfileRequest | ProfileResponse | Discover supported transactions and capabilities. |
PunchOutSetupRequest | PunchOutSetupResponse | Create or edit a punchout session and get a redirect URL to the PrintNow editor. |
OrderRequest | Status only | Submit an order with line items, pricing, and addresses. |
Profile Request
Returns the transactions supported by PrintNow's cXML endpoint. Procurement systems typically call this first to discover capabilities.
Example Request
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE cXML SYSTEM "http://xml.cxml.org/schemas/cXML/1.2.014/cXML.dtd">
<cXML payloadID="unique-id@example.com" timestamp="2026-01-15T12:00:00-05:00">
<Header>
<!-- credentials as described above -->
</Header>
<Request>
<ProfileRequest/>
</Request>
</cXML>Response
Returns a ProfileResponse listing two supported transactions:
| Transaction | URL | Options |
|---|---|---|
PunchOutSetupRequest | https://api.printnow.com/cxml | operationAllowed: create, editFlow: 1UsePricing: 1ItemNumber: 1ModelNumber: 1IntegrationId: 1CategoryId: 1 |
OrderRequest | https://api.printnow.com/cxml | None |
PunchOut Setup Request
Creates or edits a punchout session and returns a URL that redirects the user to the PrintNow storefront editor.
Operations
| Operation | Description |
|---|---|
create | Start a new punchout session. The user is directed to the storefront to design a product. |
edit | Resume an existing session. See Editing a Session for what must match the original create request. |
Flow Types
The Flow extrinsic controls what the user sees when they land on the storefront:
| Flow | Required Extrinsics | Behavior |
|---|---|---|
product | One of: ItemNumber, ModelNumber, or IntegrationId | Opens a specific product in the editor. Optionally set UsePricing=true to capture PrintNow pricing data. |
category | CategoryId | Opens a product category for the user to browse and select from. |
You must provide either product identifiers or a category ID -- not both. The endpoint validates this and returns 400 Bad Request if the constraint is violated.
Extrinsics
| Name | Required | Description |
|---|---|---|
Flow | Yes | product or category -- determines the user experience. |
ItemNumber | Conditional | Product item number (for product flow). |
ModelNumber | Conditional | Product model number (for product flow). |
IntegrationId | Conditional | Product integration ID (for product flow). |
CategoryId | Conditional | Category ID to browse (for category flow). |
UsePricing | No | Set to true to capture PrintNow pricing data during the session (product flow only). |
ConfigId | Edit only | UUID of an existing punchout session to resume. This is the ConfigId returned on the order message. |
EditorParam.<name> | No (repeatable) | A value passed to the Print Editor and returned on the order message. See Editor Parameters. |
Example Request (Create)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE cXML SYSTEM "http://xml.cxml.org/schemas/cXML/1.2.014/cXML.dtd">
<cXML payloadID="unique-id@example.com" timestamp="2026-01-15T12:00:00-05:00">
<Header>
<!-- credentials -->
</Header>
<Request>
<PunchOutSetupRequest operation="create">
<BuyerCookie>session-abc-123</BuyerCookie>
<Extrinsic name="Flow">product</Extrinsic>
<Extrinsic name="IntegrationId">BC-001</Extrinsic>
<Extrinsic name="UsePricing">true</Extrinsic>
<BrowserFormPost>
<URL>https://procurement.example.com/callback</URL>
</BrowserFormPost>
<Contact role="endUser">
<Name xml:lang="en">Jane Smith</Name>
<Email>jane@example.com</Email>
</Contact>
</PunchOutSetupRequest>
</Request>
</cXML>Response
Returns a PunchOutSetupResponse with a redirect URL:
<Response>
<Status code="200" text="OK"/>
<PunchOutSetupResponse>
<StartPage>
<URL>https://yourstore.w2p.com/punchout.aspx?uid=a1b2c3d4-...</URL>
</StartPage>
</PunchOutSetupResponse>
</Response>User Resolution
The endpoint resolves the end user from <Contact role="endUser">:
- Match by email -- Looks for an existing customer on the storefront with the contact's email address.
- Create account -- If no match, creates a new customer account using the contact's name and email.
- Create temp user -- If no contact is provided, creates a temporary user (same behavior as PIPO temp users).
New user creation fires the customer_created webhook.
Editor Parameters
Editor parameters pass values into the Print Editor on a create request. They can swap a tagged image, show or hide it, or recolor it from the storefront's palette. Their values come back on the order message, so you can also use them to round-trip your own values, such as a correlation ID.
Naming
- Send each parameter as an extrinsic named
EditorParam.<name>, for exampleEditorParam.Background. - The
EditorParam.prefix is case-insensitive. <name>is case-sensitive. To affect the design, it must exactly match the tag name of an image in the product template.
What the Value Does
The format of the value decides what happens to the tagged image:
| Value | Effect on the tagged image | Example |
|---|---|---|
| A number | Swaps it to that image ID. | EditorParam.Logo = 1234 |
true / false | Shows or hides it. | EditorParam.Badge = false |
from,to pairs separated by ; | Recolors it: each from color in its color map becomes to. | EditorParam.Background = Red,Blue;White,Black |
Color Rules
- Colors can be palette color names or hex values (with or without
#). They are case-insensitive. - Both colors in a pair must be in the storefront's palette. Otherwise the pair is ignored.
- A pair recolors an entry in the image's color map when its
fromcolor matches either the original artwork color or the current one.
Your Own Values
- A name that matches no tagged image has no effect in the editor. It comes back unchanged on the order message.
- Use this to round-trip your own identifiers, for example
EditorParam.correlationId. - Only extrinsics with the
EditorParam.prefix are returned. Other extrinsics you send are not.
Reserved Names
These names are rejected with 400 Bad Request, as is an empty name (EditorParam.). They are case-insensitive:
productid, epi, epw, tpsc, token, cru, s, uid, qty
Create Requests Only
Editor parameters apply on the create operation. On edit they are checked for reserved names, then ignored. See Editing a Session.
Example Request (Create with Editor Parameters)
<PunchOutSetupRequest operation="create">
<BuyerCookie>session-abc-123</BuyerCookie>
<Extrinsic name="Flow">product</Extrinsic>
<Extrinsic name="ItemNumber">BC-100</Extrinsic>
<Extrinsic name="EditorParam.Background">Red,Blue</Extrinsic>
<Extrinsic name="EditorParam.Logo">1234</Extrinsic>
<Extrinsic name="EditorParam.Badge">false</Extrinsic>
<Extrinsic name="EditorParam.correlationId">abc-123</Extrinsic>
<BrowserFormPost>
<URL>https://procurement.example.com/callback</URL>
</BrowserFormPost>
<Contact role="endUser">
<Name xml:lang="en">Jane Smith</Name>
<Email>jane@example.com</Email>
</Contact>
</PunchOutSetupRequest>Editing a Session
An edit request resumes the session only when all of these match the original create request. Otherwise it returns 404 Not Found:
- The
ConfigIdextrinsic (the session UUID returned asConfigIdon the order message). - The
BuyerCookie. - The
BrowserFormPostURL. - The API token in
<Sender>.
No other extrinsics are needed. Flow, product identifiers, UsePricing, and Contact are ignored on an edit.
When the session has editor parameters:
- The editor reopens the saved design with the shopper's changes. The original editor parameters are not re-applied.
EditorParam.*extrinsics on an edit request are checked for reserved names, then ignored.- The order message returns the current values for names the editor matched. Every other name keeps its value from the create request, so you cannot supply a new correlation ID on an edit.
Example Request (Edit, Minimum)
<PunchOutSetupRequest operation="edit">
<BuyerCookie>session-abc-123</BuyerCookie>
<Extrinsic name="ConfigId">a1b2c3d4-e5f6-...</Extrinsic>
<BrowserFormPost>
<URL>https://procurement.example.com/callback</URL>
</BrowserFormPost>
</PunchOutSetupRequest>PunchOut Order Message
When the shopper finishes, PrintNow posts a PunchOutOrderMessage back to the BrowserFormPost URL from the setup request.
- It is posted as a browser form field named
cxml-urlencoded. BuyerCookieis returned unchanged from the setup request.- Each design is one
ItemIn:quantityis the ordered quantity.SupplierPartIDis the PrintNow product ID.UnitPriceand the headerTotalare included when PrintNow pricing is used.Descriptionis the product's short description.UnitOfMeasureisEA.
ItemIn Extrinsics
| Extrinsic | When present | Value |
|---|---|---|
ConfigId | Always | Punchout session UUID. Send it back on an edit. |
ProofUrl | Always | Download link for the proof PDF. |
ThumbnailUrl | Always | Product thumbnail image. |
ProductId | Always | PrintNow product ID. |
ItemNumber / ModelNumber / IntegrationId | When set on the product | The product's identifiers. |
StandardSize or CustomSize | With PrintNow pricing | Size name, or W x H. |
Colors | With PrintNow pricing | Color/pages selection name. |
| One per pricing option (the option's name) | With PrintNow pricing | Selected option value. |
Weight | With PrintNow pricing, when above 0 | Calculated weight. |
EditorParam.<name> | One per editor parameter sent at setup | See Returned Editor Parameter Values. |
Returned Editor Parameter Values
- Every
EditorParam.<name>sent on the create request comes back on eachItemIn, with the same name. - A name the editor matched to a tagged image carries its current value, which reflects the shopper's changes. Any other name carries the original value, unchanged.
- Image swap: the current image ID.
- Show/hide:
truewhen the image is visible,falsewhen hidden. - Recolor:
original,currentpairs separated by;. These cover the image's whole color map, not just the pairs sent.- Each color is a palette name when it is in the palette, and bare hex without
#when it is not. For example,Red,123456means the shopper picked a color outside the palette. - So the returned value can differ from what was sent, even when nothing changed.
- Each color is a palette name when it is in the palette, and bare hex without
Example ItemIn
This example follows the create request above, after the shopper changed Blue to White. Pricing extrinsics are left out.
<ItemIn quantity="250">
<ItemID>
<SupplierPartID>98765</SupplierPartID>
</ItemID>
<ItemDetail>
<UnitPrice>
<Money currency="USD">0.42</Money>
</UnitPrice>
<Description xml:lang="en">Business Card</Description>
<UnitOfMeasure>EA</UnitOfMeasure>
<Classification domain="UNSPSC">0</Classification>
<Extrinsic name="ConfigId">a1b2c3d4-e5f6-...</Extrinsic>
<Extrinsic name="ProofUrl">https://yourstore.w2p.com/download.ashx?pid=98765</Extrinsic>
<Extrinsic name="ThumbnailUrl">https://yourstore.w2p.com/thumbnails/p/98765</Extrinsic>
<Extrinsic name="ProductId">98765</Extrinsic>
<Extrinsic name="ItemNumber">BC-100</Extrinsic>
<Extrinsic name="EditorParam.Background">Red,White</Extrinsic>
<Extrinsic name="EditorParam.Logo">1234</Extrinsic>
<Extrinsic name="EditorParam.Badge">false</Extrinsic>
<Extrinsic name="EditorParam.correlationId">abc-123</Extrinsic>
</ItemDetail>
</ItemIn>Order Request
Submits an order from a completed punchout session. The order is created in PrintNow with line items, pricing, and addresses from the cXML order envelope.
Example Request
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE cXML SYSTEM "http://xml.cxml.org/schemas/cXML/1.2.014/cXML.dtd">
<cXML payloadID="unique-id@example.com" timestamp="2026-01-15T12:00:00-05:00">
<Header>
<!-- credentials -->
</Header>
<Request>
<OrderRequest>
<OrderRequestHeader orderID="PO-2026-001" type="new">
<Total>
<Money currency="USD">150.00</Money>
</Total>
<ShipTo>
<Address>
<Name xml:lang="en">Acme Corp</Name>
<PostalAddress>
<DeliverTo>Jane Smith</DeliverTo>
<Street>123 Main St</Street>
<City>New York</City>
<State>NY</State>
<PostalCode>10001</PostalCode>
<Country isoCountryCode="US">United States</Country>
</PostalAddress>
</Address>
</ShipTo>
<BillTo>
<Address>
<Name xml:lang="en">Acme Corp</Name>
<PostalAddress>
<Street>123 Main St</Street>
<City>New York</City>
<State>NY</State>
<PostalCode>10001</PostalCode>
<Country isoCountryCode="US">United States</Country>
</PostalAddress>
</Address>
</BillTo>
<Shipping>
<Money currency="USD">10.00</Money>
<Description xml:lang="en">Ground Shipping</Description>
</Shipping>
<Tax>
<Money currency="USD">12.50</Money>
</Tax>
<Contact role="endUser">
<Name xml:lang="en">Jane Smith</Name>
<Email>jane@example.com</Email>
</Contact>
</OrderRequestHeader>
<ItemOut quantity="1">
<ItemID>
<SupplierPartID>42</SupplierPartID>
</ItemID>
<ItemDetail>
<UnitPrice>
<Money currency="USD">127.50</Money>
</UnitPrice>
<Description xml:lang="en">Business Cards</Description>
<UnitOfMeasure>EA</UnitOfMeasure>
<Classification domain="custom">print</Classification>
<Extrinsic name="ConfigId">a1b2c3d4-e5f6-...</Extrinsic>
</ItemDetail>
</ItemOut>
</OrderRequest>
</Request>
</cXML>Order Processing
When an order is submitted:
- User resolution -- The customer is identified from the
<Contact>element (same logic as PunchOut Setup). - Order creation -- An order record is created with the storefront's initial (lowest-sequence) order status.
- Pricing -- Order totals are parsed from
<Total>,<Tax>, and<Shipping>. The item subtotal is calculated as total minus tax minus shipping. - Addresses -- Billing and shipping addresses are parsed from
<BillTo>and<ShipTo>. If no shipping address is provided, the billing address is used. Custom extrinsicsCustomerCompany,CustomerName, andIsResidentialare supported on<PostalAddress>. - Line items -- Each
<ItemOut>becomes an order item:- If the
SupplierPartIDmatches a PrintNow product ID and aConfigIdextrinsic links to a valid punchout session, PrintNow system pricing (size, color, turnaround, options) is attached. - Otherwise, an external product record is created using the part ID and description.
- If the
- File processing -- Print-ready file generation (merge) is triggered automatically.
- Webhook -- The
order_createdwebhook is fired.
Address Extrinsics
The following custom extrinsics can be added to <PostalAddress> elements:
| Extrinsic | Description |
|---|---|
CustomerCompany | Company name for the address. If omitted, the <Address> name is used. |
CustomerName | Contact person name. If omitted, the <DeliverTo> value is parsed as first/last name. |
IsResidential | Set to true, 1, or yes to flag as a residential address (affects shipping rate calculation). |
Error Handling
All cXML responses follow the standard cXML envelope format with a <Status> element:
<Response>
<Status code="200" text="OK"/>
</Response>| Code | Text | Cause |
|---|---|---|
200 | OK | Request processed successfully. |
400 | Bad Request | Invalid flow/product/category combination, missing required data, or an invalid EditorParam name (empty or reserved). |
401 | Unauthorized | Invalid API credentials, DUNS mismatch, or storefront not found. |
404 | Not Found | Punchout session not found (edit operation), or its BuyerCookie, BrowserFormPost URL, or API token does not match the create request. |
406 | Not Acceptable | Missing or empty cXML envelope. |
415 | Unsupported Media Type | Content-Type is not application/xml. |
501 | Not Implemented | Unsupported request type or operation (e.g., delete orders). |
Storefront Configuration
For cXML integration, each storefront must have a Punchout ID Type and Punchout ID configured. These values are matched against the <From> credential in the cXML header to identify which storefront the request targets.
Common configurations:
| Punchout ID Type | Example | Use Case |
|---|---|---|
DUNS | 123456789 | Standard DUNS number identification. |
NetworkId | AN01000000001 | Ariba Network ID. |
| Custom domain | procurement.example.com | Custom identifier for the procurement system. |
Related Pages
- Authentication — API token/key credentials used in the cXML Sender element
- PIPO — REST-based punch-in/punch-out alternative to cXML
- Webhooks — receive order_created and customer_created events from cXML submissions
- Orders — retrieve and manage orders created through cXML