AI Protocol Mappers
Where a Message Mapper reshapes JSON into different JSON, a Protocol Mapper converts between the JSON an agent always sees and the upstream's actual wire format — XML, a SOAP 1.1 envelope, or form-urlencoded — so you can put a modern JSON tool interface in front of a legacy service without changing anything on the upstream side.
Like message mappers, a protocol mapper applies to one OpenAPI operationId, in one direction (request or response), and only one mapper of each direction can exist per operation.
Fields
| Field | Notes |
|---|---|
wire_format | xml or form_urlencoded |
root_element | XML only — the top-level element/tag name to wrap the JSON payload in when encoding |
soap_envelope | If true, the XML is wrapped in (or unwrapped from) a SOAP 1.1 Envelope/Body |
soap_action | Sent as the SOAPAction header — only meaningful for a request-direction mapper with soap_envelope: true |
content_type_override | Overrides the Content-Type header that would otherwise be inferred from wire_format/soap_envelope |
test_cases | [{json_sample, wire_sample}] pairs used by the test endpoint |
Conversion rules
- XML element and attribute names come from your JSON keys and are validated: a key that isn't a valid XML name (for example
a><b) is rejected, so JSON input can't inject markup into the request sent upstream.root_elementis validated when you save. - Namespaces are removed from element and attribute names when decoding, so a SOAP response decodes to plain keys —
{"GetRateResponse": {"Rate": {"@currency": "INR", "#text": "83.50"}}}rather than{http://…}Rate. - Form-urlencoded encoding accepts flat values and lists of scalars (a list becomes a repeated key,
tag=a&tag=b). Nested objects have no form equivalent and are rejected with a clear error — flatten them with a request Message Mapper first. When decoding, a repeated key becomes a list. - Untrusted XML (upstream responses and samples) is parsed with protections against entity-expansion and external-entity attacks; such documents are refused.
soap_actionandcontent_type_overridecan't contain line breaks.
Deterministic detection, AI only for the ambiguous cases
Converting well-formed XML, a SOAP envelope, or form-urlencoded data is entirely deterministic — parsing them doesn't need an LLM. POST /protocol-mappers/detect takes a raw sample and returns a proposed config with a confidence level:
POST /protocol-mappers/detect
{ "sample": "<Envelope xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\"><Body><GetPet><id>1</id></GetPet></Body></Envelope>" }{ "wire_format": "xml", "soap_envelope": true, "root_element": "GetPet", "confidence": "high" }- A well-formed SOAP envelope or plain XML document detects with
confidence: "high"—wire_format,root_element, andsoap_envelopeare all filled in directly. - A
key=value&...-shaped sample detects asform_urlencodedwithconfidence: "medium". - Anything that fails to parse as XML, or already looks like JSON, comes back
confidence: "low"with areasonand nowire_format(a sample that's already JSON needs no protocol mapper at all).
POST /protocol-mappers/generate is the AI fallback for exactly the ambiguous cases above (anything not confidence: "high") — it's used to name a root_element or confirm SOAP framing on an unusual sample, never to parse the format itself:
{ "root_element": "GetPetResponse", "soap_envelope": true, "reason": "...", "source": "ai" }("source" is "deterministic" if the high-confidence deterministic result was returned as-is, "ai" if the LLM fallback ran.) As with Message Mapper generation, the proposal is never auto-applied — review and save it like any other mapper field.
Endpoints
All under /api/v1/api-definitions/{api_definition_id}, mirroring the Message Mapper API shape:
| Endpoint | Description |
|---|---|
GET /protocol-mappers | List all protocol mappers for this API |
POST /protocol-mappers | Create a mapper |
GET /protocol-mappers/{mapper_id} | Get one mapper |
PUT /protocol-mappers/{mapper_id} | Update a mapper (partial) |
DELETE /protocol-mappers/{mapper_id} | Delete a mapper |
POST /protocol-mappers/detect | Deterministic wire-format detection from a raw sample |
POST /protocol-mappers/generate | AI-assisted fallback for ambiguous samples |
POST /protocol-mappers/{mapper_id}/test | Round-trip test against saved test_cases |
Creating, editing, or deleting a mapper requires the same roles as Message Mappers — api_developer, lifecycle_manager, space_admin, or admin.
Testing a mapper
The test compares by decoding both sides, not a brittle exact-string match — XML attribute order or whitespace can legitimately differ while being semantically identical. For each {json_sample, wire_sample} test case: json_sample is encoded to wire format and immediately decoded back, and compared against the decoded wire_sample (or against json_sample itself if no wire_sample is given). Pass/fail is cached the same way as Message Mapper tests (last_test_passed, last_tested_at).
Related
- AI Message Mappers — JSON-to-JSON reshaping; runs before protocol encoding on the request side, after protocol decoding on the response side
- API Gateway — the exact pipeline order both mapper types run in on a live call