If you work anywhere near commerce, you already know the problem. The order is the most important object in the business — it is what gets fulfilled, billed, recognized as revenue, and shipped to the customer — and yet the order travels through the enterprise in whatever shape the originating platform happened to emit fifteen years ago. SAP Commerce (Hybris) emits an XML order envelope that predates TM Forum Open APIs. Salesforce Commerce Cloud’s OCAPI order XML predates them too. The downstream systems that need to read those orders — billing, provisioning, customer notifications, the warehouse, the dashboards, and now the AI agents — each end up writing their own little translator. Fifteen translators for one shape. None of them traceable. None of them observable. None of them talking to each other.
This is exactly the kind of seam a Naftiko capability is built to close.
What Naftiko actually is
Naftiko is an open framework for wrapping any upstream API — legacy, modern, internal, third-party — as a versioned capability. A capability is a single YAML file that names what the capability consumes (the upstream API in its real wire-level shape), and what it exposes (one or more clean, governed surfaces on top of it). The engine that reads the YAML runs as a container. The exposed surfaces can be REST endpoints, MCP tools for AI agents, gRPC, GraphQL, or all of the above — from the same spec, with the same auth, the same observability, the same tests.
The point is not to write yet another integration. The point is to stop writing integrations and start declaring them. One capability YAML replaces the fifteen translators. When the upstream changes, you change the consumes block. When a new downstream — say, an agent runtime, or a TMF-aligned partner — needs the same data in a different shape, you add an exposes block. The capability is the contract. The engine handles everything else.
Why convert legacy order XML to TMF622 at all
TM Forum’s TMF622 Product Ordering Management API v5.0 is the closest thing the industry has to a universal ordering vocabulary. It is REST. It is JSON. It is versioned. It carries productOrderItem, relatedParty, requestedStartDate, state, productOffering, itemPrice, note, agreement, payment, and billingAccount as first-class fields. Every modern BSS, every API gateway, every TMF-aligned partner integration, every commerce-aware AI agent already knows how to read it.
What that means in practice is the difference between fifteen one-off translators and one published contract. If your fulfillment partner speaks TMF622, your billing platform speaks TMF622, your portal speaks TMF622, and your agent stack speaks TMF622, then the only thing left to do is normalize whatever your Hybris or Commerce Cloud instance is actually emitting into that one shape. Once. Behind a capability. With observability on the seam.
The legacy XML is not going anywhere. Rip-and-replace projects on commerce platforms are how careers end, not how value gets delivered. The right move is to wrap, not replace — let Hybris keep doing what Hybris does well, let Commerce Cloud keep being the storefront, and put a Naftiko capability in front of them that hands the rest of the enterprise a TMF622 ProductOrder on every read.
What the capability looks like
The shape is intentionally simple. Two consumes blocks — one for the SAP Commerce OCC v2 order resource, one for the Salesforce Commerce Cloud OCAPI order resource. Both speak XML. Both authenticate with a bearer token. Both expose a per-order GET that returns the legacy envelope unchanged. On top of those, one exposes block per surface: MCP for agents, REST for humans and dashboards. The output of every exposed call is a clean TMF622 v5 ProductOrder JSON.
naftiko: "1.0.0-alpha2"
info:
title: Manage Commerce Orders — TMF622
description: >
Wraps SAP Commerce (Hybris) and Salesforce Commerce Cloud order XML
endpoints and exposes every order as a TMF622 v5 ProductOrder via REST
and MCP. One capability, two upstreams, three surfaces, one contract.
binds:
- namespace: env
keys:
HYBRIS_TOKEN: HYBRIS_TOKEN
SFCC_TOKEN: SFCC_TOKEN
capability:
consumes:
- namespace: hybris
type: http
baseUri: "https://commerce.example.com"
description: "SAP Commerce (Hybris) OCC v2 order resource — XML."
authentication:
type: bearer
token: "{{HYBRIS_TOKEN}}"
resources:
- name: order
path: "/occ/v2/{{site_id}}/orders/{{order_code}}"
operations:
- name: get-hybris-order
method: GET
headers:
- name: Accept
value: "application/xml"
inputParameters:
- name: site_id
in: path
required: true
- name: order_code
in: path
required: true
- namespace: sfcc
type: http
baseUri: "https://commerce.demandware.net"
description: "Salesforce Commerce Cloud OCAPI shop order resource — XML."
authentication:
type: bearer
token: "{{SFCC_TOKEN}}"
resources:
- name: order
path: "/s/{{site_id}}/dw/shop/v21_3/orders/{{order_no}}"
operations:
- name: get-sfcc-order
method: GET
headers:
- name: Accept
value: "application/xml"
inputParameters:
- name: site_id
in: path
required: true
- name: order_no
in: path
required: true
exposes:
- type: mcp
address: "0.0.0.0"
port: 3061
namespace: manage-commerce-orders
description: >
TMF622 v5 ProductOrder fetcher for SAP Commerce (Hybris) and
Salesforce Commerce Cloud. One tool per platform, identical
output shape.
tools:
- name: get-hybris-order-tmf622
description: "Fetch a Hybris order by site and order code, return as a TMF622 v5 ProductOrder."
hints:
readOnly: true
inputParameters:
- name: site_id
type: string
required: true
- name: order_code
type: string
required: true
call: hybris.get-hybris-order
transform:
engine: xslt
template: "transforms/hybris-to-tmf622.xsl"
- name: get-sfcc-order-tmf622
description: "Fetch a Salesforce Commerce Cloud order by site and order number, return as a TMF622 v5 ProductOrder."
hints:
readOnly: true
inputParameters:
- name: site_id
type: string
required: true
- name: order_no
type: string
required: true
call: sfcc.get-sfcc-order
transform:
engine: xslt
template: "transforms/sfcc-to-tmf622.xsl"
- type: rest
address: "0.0.0.0"
port: 8091
namespace: manage-commerce-orders-rest
resources:
- name: hybris-order
path: "/productOrder/hybris/{site_id}/{order_code}"
operations:
- name: get-hybris-order-tmf622
method: GET
inputParameters:
- name: site_id
in: path
required: true
- name: order_code
in: path
required: true
call: hybris.get-hybris-order
transform:
engine: xslt
template: "transforms/hybris-to-tmf622.xsl"
- name: sfcc-order
path: "/productOrder/sfcc/{site_id}/{order_no}"
operations:
- name: get-sfcc-order-tmf622
method: GET
inputParameters:
- name: site_id
in: path
required: true
- name: order_no
in: path
required: true
call: sfcc.get-sfcc-order
transform:
engine: xslt
template: "transforms/sfcc-to-tmf622.xsl"
The two consumes blocks each name the legacy XML resource exactly as it lives today. The exposes block declares one MCP tool and one REST route per upstream. The transform blocks pin the conversion to a versioned XSLT — the order XML goes in, a TMF622 v5 ProductOrder JSON comes out. That XSLT is the single point of truth for how a Hybris order item becomes a productOrderItem, how the buyer block becomes a relatedParty with role customer, how the order total becomes an itemPrice, and how the order status becomes the TMF622 state. One file. One review surface. One diff when the mapping changes.
Traceable, observable, integrated into AI
This is where the capability stops being a translator and starts being a control surface. Three things change the moment the legacy XML moves behind a Naftiko capability.
Traceable. Every read of a Hybris or Commerce Cloud order now flows through one engine. That engine emits a trace per call: which upstream was hit, which credentials were used, which XSLT version produced the output, how long the upstream took, how long the transform took, what the caller asked for, what was returned. Today, when a billing dispute lands on someone’s desk, the answer to “what shape did the order actually arrive in?” is a guess. Behind a capability, it is a query.
Observable. The capability is one named workload — one set of metrics, one dashboard, one alerting target. If Hybris starts returning a malformed envelope at 2 a.m., you do not find out from a billing reconciliation report three days later. You find out from the capability’s error rate. If Commerce Cloud’s OCAPI starts shedding requests under load, you see it in one place, not in fifteen translator logs scattered across teams.
Integrated into AI. This is the part that did not exist when the legacy XML was written. The same capability that hands a TMF622 ProductOrder to your billing system over REST also hands the exact same shape to an AI agent over MCP — same auth, same trace, same observability, same XSLT version. When a support agent’s LLM asks “what is order 4815162342 in?” the answer comes through the same pipe the rest of the business already trusts. You do not stand up a separate AI integration. You add an exposes block.
The bigger move
Hybris and Commerce Cloud are not the problem. They are doing what they were built to do. The problem is that the rest of the enterprise has been quietly paying the cost of every team writing its own order translator. A capability turns that cost into one file, one container, one contract, one trace.
If you have a commerce platform emitting order XML today and a roadmap that says “TMF-align everything,” start with one capability. Hybris on Monday. Commerce Cloud on Tuesday. By Friday every downstream — billing, fulfillment, the dashboards, the agent stack — is reading TMF622 v5 from one URL, and the mapping is one XSLT review away from changing. That is what wrap-not-replace actually looks like in code.