General

MuleSoft Mastery: From Zero to Hero | Ch.15

Governance flags problems; a custom policy fixes them at runtime. This complete, step-by-step guide builds a Mule Gateway policy from an empty folder to a published asset โ€”โ€ฆ

MuleSoft Mastery: From Zero to Hero | Ch.15
Chapter 15 ยท MuleSoft from Zero to Hero

Governance tells you an API is out of line. A custom policy actually does something about it โ€” at runtime, on every request. This is the complete build: from an empty folder to a policy live in Exchange and applied across your whole fleet.

SeriesMuleSoft Zero โ†’ Hero Chapter15 of 16 PublishedJune 19, 2026 Read~28 min Custom Policies Mule Gateway PDK Exchange

In Chapter 14 you made the platform enforce standards โ€” but governance only flags problems. It can’t rewrite a header, call your security service, or mask a field in a live response. For that you need to change behaviour at the gateway itself, and the out-of-the-box policies only go so far. This chapter is the part every serious MuleSoft team eventually reaches: writing your own policy, from scratch, the official way.

Companion source code

The companion repo carries a ready-to-build policy project: the archetype output, a template.xml with a guard and a response-header transform, a fully-annotated config YAML, and the Maven settings for publishing to Exchange.

โ†’ github.com/nestaconnect/mulesoft-from-zero-to-hero

By the end of this chapter you will:

  • Configure Maven to reach MuleSoft’s archetype and Exchange repositories
  • Generate a policy project and understand what every file is for
  • Write policy logic in template.xml and truly grasp execute-next
  • Define the config form API Manager shows, in YAML
  • Modify requests and responses with the HTTP Policy Transform Extension
  • Package, publish to Exchange, apply an API, and roll out fleet-wide with Automated Policies
  • Study a real, production policy end to end: Treblle observability

01 ยท Why & How โ€” The Four-Step Workflow

A custom policy is exactly what it sounds like: your own logic, injected into the gateway, applied to any API you choose. It can rewrite headers and payloads, add authentication, call an external system, log, cache, throttle โ€” anything the Mule runtime can do. And the path from idea to running policy is always the same four moves.

1 ยท DEVELOP template.xml + yaml 2 ยท PACKAGE mvn clean package 3 ยท PUBLISH โ†’ Exchange 4 ยท APPLY API Manager
Develop the logic, package it into a JAR, publish that JAR to Exchange, then apply it to any API from API Manager. Master these four and you can build anything.

02 ยท Setup โ€” Teaching Maven Where to Look

You’ll need JDK 8, 11, or 17, Maven 3.8+, and an Anypoint account with an Exchange Contributor (or Administrator) role. You’ll also need your Organization ID โ€” grab it from Access Management โ†’ Organization (it’s the UUID in the URL).

The one catch: the policy archetype isn’t on Maven Central. You have to point Maven at MuleSoft’s repository โ€” and, while you’re in ~/.m2/settings.xml, add the Exchange credentials you’ll publish with.

~/.m2/settings.xml โ€” archetype repository + Exchange credentials
<profiles>
  <profile>
    <id>archetype-repository</id>
    <repositories>
      <repository>
        <id>archetype</id>
        <name>Mule Repository</name>
        <url>https://repository.mulesoft.org/nexus/content/repositories/public</url>
        <releases><enabled>true</enabled><checksumPolicy>fail</checksumPolicy></releases>
        <snapshots><enabled>true</enabled><checksumPolicy>warn</checksumPolicy></snapshots>
      </repository>
    </repositories>
  </profile>
</profiles>

<!-- the server id must match the Exchange repository id in your pom.xml -->
<servers>
  <server>
    <id>exchange-server</id>
    <username>${anypoint.username}</username>
    <password>${anypoint.password}</password>
  </server>
</servers>
Keep credentials out of the repo

settings.xml lives in your home directory, not your project โ€” never commit Anypoint credentials to version control. In CI, inject them as masked environment variables or a secrets store, and confirm the account has permission to publish to Exchange before you try to deploy.

03 ยท Generate โ€” Scaffolding the Project

With Maven configured, the archetype builds the whole skeleton for you. Make a directory, drop into it, and run the generator โ€” activating the archetype-repository profile you just defined:

Shell โ€” generate the policy project from the official archetype
mkdir my-custom-policy && cd my-custom-policy

mvn -Parchetype-repository archetype:generate \
  -DarchetypeGroupId=org.mule.tools \
  -DarchetypeArtifactId=api-gateway-custom-policy-archetype \
  -DarchetypeVersion=1.2.0 \
  -DgroupId=${orgId} \
  -DartifactId=${policyName} \
  -Dversion=1.0.0 \
  -Dpackage=mule-policy

# add -DencryptionSupported=true to allow encrypted configuration values

Set ${orgId} to your Organization ID (the policy uploads there) and ${policyName} to the policy’s artifact name. Maven then prompts for a policyDescription and a policyName identifier โ€” fill those in and the project is ready.

04 ยท The Four Files โ€” What Each One Does

The archetype produces a deliberately small project. Four files, four jobs:

Generated project structure
my-custom-policy/
โ”œโ”€โ”€ my-custom-policy.yaml      # the config form shown in API Manager
โ”œโ”€โ”€ mule-artifact.json         # policy descriptor for the packager
โ”œโ”€โ”€ pom.xml                    # build + publish to Exchange
โ””โ”€โ”€ src/
    โ””โ”€โ”€ main/
        โ””โ”€โ”€ mule/
            โ””โ”€โ”€ template.xml   # the actual policy logic

pom.xml โ€” the build. Its groupId is your org ID (leave it as generated), its packaging is mule-policy so the packager can build the JAR, and its distributionManagement points at your Exchange. The mule-maven-plugin packages the policy; the deploy plugin uploads both the JAR and the YAML.

mule-artifact.json โ€” the descriptor the mule-maven-plugin needs, the same file a Mule app uses. One rule to remember: policies can’t export resources or Java packages, and they can’t use connectors that do (no Java or Spring modules).

my-custom-policy.yaml โ€” the configuration UI. This is what renders the parameter form in API Manager. Skip it and your policy can’t be configured through the platform at all. (Section 7.)

src/main/mule/template.xml โ€” the logic. By default the archetype writes a policy that simply sets the response to "Hello World!". Everything interesting you build here. (Section 5.)

05 ยท Anatomy โ€” Inside template.xml

A policy is written directly in XML โ€” no drag-and-drop โ€” and it looks a little unfamiliar at first. Here’s the default the archetype generates, which is the smallest complete policy there is:

template.xml โ€” the generated “Hello World” policy
<mule xmlns="http://www.mulesoft.org/schema/mule/core"
      xmlns:http-policy="http://www.mulesoft.org/schema/mule/http-policy">

  <http-policy:proxy name="{{{policyId}}}-custom-policy">   <!-- (1) -->
    <http-policy:source>                                <!-- (2) -->
      <http-policy:execute-next/>                       <!-- (3) -->
      <set-payload value="Hello World!"/>
    </http-policy:source>
  </http-policy:proxy>
</mule>

Three elements carry the whole model:

  • (1) <http-policy:proxy> โ€” the wrapper for every policy. {{{policyId}}} is a Handlebars variable the runtime substitutes when the policy is applied. A proxy holds a source block, an operation block, or both.
  • (2) <http-policy:source> โ€” logic for inbound traffic: it wraps what happens around the API’s HTTP Listener.
  • (3) <http-policy:execute-next/> โ€” the hinge. It hands control to the next policy (or the app flow). Everything before it runs on the way in; everything after runs on the way back out. Omit it and the chain stops dead โ€” which is exactly how a policy blocks a request.

06 ยท execute-next โ€” The Order of Everything

Once you internalize execute-next, policies stop being mysterious. Think of stacked policies as nested shells around your flow. A policy with a lower order sits on the outside; the flow is always in the very middle.

A1 โ†’ B1 โ†’ FLOW โ†’ B2 โ†’ A2 POLICY A ยท order 1 POLICY B ยท order 2 APP FLOW ยท F1A1 โ–ธ B1 โ–ธ โ—‚ A2 โ—‚ B2 Before execute-next runs inbound (green โ–ธ). After execute-next runs outbound (pink โ—‚). Lower order = outermost shell.
Two policies around one flow. The request threads inward โ€” A1, B1 โ€” hits the flow (F1), then unwinds outward โ€” B2, A2. That single rule explains every multi-policy interaction you’ll ever debug.
Position in sourceRunsUse it for
Before execute-nextOn the way in (request)Auth checks, add request headers, validate, block
After execute-nextOn the way out (response)Add response headers, transform/log the response

Because skipping execute-next stops the chain, conditional access is just a <choice>: call it when the request is valid, and respond directly when it isn’t.

template.xml โ€” block the request unless it carries an Authorization header
<http-policy:proxy name="{{{policyId}}}-guard">
  <http-policy:source>
    <choice>
      <when expression="#[!isEmpty(attributes.headers['authorization'])]">
        <http-policy:execute-next/>          <!-- valid โ†’ continue -->
      </when>
      <otherwise>                              <!-- invalid โ†’ never continue -->
        <http-transform:set-response statusCode="401">
          <http-transform:body>#['Missing Authorization header']</http-transform:body>
        </http-transform:set-response>
      </otherwise>
    </choice>
  </http-policy:source>
</http-policy:proxy>

07 ยท The Config UI โ€” Parameters in YAML

The YAML file is how a policy becomes reusable. API Manager reads it and renders a form; whoever applies the policy fills in the fields. Each parameter you define here is available in template.xml via Handlebars โ€” {{apiKey}}, {{maskKeywords}}, and so on. Here’s the shape, drawn from the real Treblle policy:

my-custom-policy.yaml โ€” parameters become the API Manager form
id: treblle-policy
name: Treblle API Observability
description: Logging, payload masking & observability via Treblle
category: Security
type: custom

providedCharacteristics:
  - Logs API traffic to Treblle
  - Masks sensitive data
requiredCharacteristics:
  - Requires HTTP protocol

configuration:
  - propertyName: apiKey
    name: API Key
    description: Your Treblle API key
    type: string
    mandatory: true
    sensitive: true            # hidden in the UI
  - propertyName: maskKeywords
    name: Mask Keywords
    description: Comma-separated fields to mask
    type: string
    defaultValue: email,password,token,ssn
    mandatory: false
  - propertyName: maskPayload
    name: Mask Entire Payload
    type: boolean
    defaultValue: false
    mandatory: false
typeRenders as
stringText input
booleanCheckbox
int / numberNumber input
enumDropdown
object / arrayNested / repeatable config
Always mark secrets sensitive

Any credential โ€” API keys, tokens, passwords โ€” should carry sensitive: true. API Manager then masks it in the form and stores it securely, instead of showing it in plain text to anyone who opens the policy configuration. Clear name and description fields aren’t cosmetic either: they’re the only guidance the next engineer gets.

08 ยท Transforming Traffic โ€” The HTTP Policy Transform Extension

Reading requests is easy; changing them is what the HTTP Policy Transform Extension is for. It adds first-class operations for adding and removing request/response headers and rewriting the message. Add the dependency (the docs cover version 3.0.0 and later โ€” use a current 3.x, not an old 1.x), and declare its namespace.

pom.xml โ€” add the transform extension
<dependency>
  <groupId>com.mulesoft.anypoint</groupId>
  <artifactId>mule-http-policy-transform-extension</artifactId>
  <version>3.0.0</version>          <!-- check for the latest 3.x -->
  <classifier>mule-plugin</classifier>
</dependency>

To stamp a header onto every response, run add-headers with outputType="response" after execute-next โ€” because responses only exist on the way back out:

template.xml โ€” add a response header after the flow returns
<mule xmlns="http://www.mulesoft.org/schema/mule/core"
      xmlns:http-policy="http://www.mulesoft.org/schema/mule/http-policy"
      xmlns:http-transform="http://www.mulesoft.org/schema/mule/http-policy-transform">
  <http-policy:proxy name="{{{policyId}}}-headers">
    <http-policy:source>
      <http-policy:execute-next/>                    <!-- run the flow first -->
      <http-transform:add-headers outputType="response">
        <http-transform:headers>#[{
          'X-Policy-Applied': 'true'
        }]</http-transform:headers>
      </http-transform:add-headers>
    </http-policy:source>
  </http-policy:proxy>
</mule>

Policies can reach outbound calls too. Alongside source, a proxy may hold an <http-policy:operation> block that wraps an HTTP Requester inside a flow โ€” its own execute-next lets you inject headers before and after each outbound request, not just the inbound one.

09 ยท Ship It โ€” Build, Publish, Apply

Two commands take you from source to a published asset. Package first โ€” it produces the deployable JAR โ€” then deploy, which uploads the JAR and the YAML to your org’s Exchange:

Shell โ€” package, then publish to Exchange
mvn clean package   # โ†’ target/my-custom-policy-1.0.0-mule-policy.jar
mvn clean deploy    # uploads the JAR + YAML to Exchange

Verify it landed: open Exchange, search by policy name, and confirm the version. To use it, go to API Manager โ†’ your API โ†’ Policies โ†’ Apply New Policy, pick your policy, fill in the form your YAML defined, and click Apply.

Automated Policies roll it out to the whole fleet

Applying a policy per API doesn’t scale past a handful. Automated Policies (API Manager โ†’ Automated Policies โ†’ Add) apply one policy, configured once, across every matching API โ€” with a rule of application by runtime (all runtimes, a Mule version range, or specific Java versions). New APIs inherit it automatically. It’s the same “tag once, governed forever” idea from Chapter 14, applied to runtime behaviour: centralized config, consistent masking, one dashboard, near-zero maintenance.

10 ยท Case Study โ€” The Treblle Observability Policy

Treblle ships an official Mule Gateway policy that gives teams full visibility into their APIs โ€” real-time logging, auto-generated docs, and payload masking โ€” without touching application code. It’s a perfect example of the pattern this whole chapter builds toward: intercept, observe, get out of the way.

OBSERVE WITHOUT SLOWING DOWN REQUEST client call TREBLLE POLICY capture ยท mask execute-next YOUR API no added latency TREBLLE async metadata fire-and-forget โ†’ Treblle servers
The policy captures and masks request metadata, ships it asynchronously to Treblle, and immediately lets the call continue to your API โ€” observability with no cost to response time.

Deploying it is the workflow you just learned, start to finish:

Shell โ€” clone, set your org, build, publish
git clone https://github.com/Treblle/treblle-mulesoft.git
cd treblle-mulesoft

# set groupId in pom.xml to your Business Group ID, then:
mvn clean package
mvn clean deploy          # โ†’ appears in Exchange as "treblle-policy"

Apply it to one API from the Policies tab with your Treblle API Key and SDK Token, choose your masking keywords โ€” or, to cover everything at once, add it as an Automated Policy. Every API, one configuration, one consolidated view of your entire API traffic.

11 ยท Recap โ€” What You Now Know

01 ยท WORKFLOW โฌก

Develop โ†’ package โ†’ publish โ†’ apply

Four repeatable steps take any idea from an empty folder to a policy applied on an API.

  • Logic in template.xml
  • JAR via Maven
  • Published to Exchange
  • Applied in API Manager
02 ยท SCAFFOLD ๐Ÿ—

The archetype does the setup

Point Maven at MuleSoft’s repo, run the archetype, and get four purpose-built files.

  • api-gateway-custom-policy-archetype:1.2.0
  • settings.xml profile + creds
  • yaml ยท json ยท pom ยท template
  • Never commit credentials
03 ยท execute-next โ‡„

The hinge of every policy

Before it runs inbound; after it runs outbound; skip it to block. Lower order = outer shell.

  • A1 โ†’ B1 โ†’ F1 โ†’ B2 โ†’ A2
  • Guard with <choice>
  • source = inbound
  • operation = outbound
04 ยท CONFIG UI โš™

YAML becomes the form

Parameters defined in YAML render in API Manager and reach the logic via Handlebars.

  • {{apiKey}} in template.xml
  • string ยท boolean ยท enum ยท โ€ฆ
  • sensitive: true for secrets
  • No YAML = no UI
05 ยท TRANSFORM โœŽ

Change the traffic

The HTTP Policy Transform Extension adds and removes headers and rewrites messages.

  • Use current 3.x, not 1.x
  • add-headers outputType="response"
  • Responses only after execute-next
  • Outbound via operation
06 ยท TREBLLE + FLEET ๐Ÿ›ฐ

Ship it everywhere

Package, deploy, apply โ€” and use Automated Policies to cover every API from one config.

  • mvn clean package / deploy
  • Observe without latency
  • Automated Policies for fleets
  • New APIs inherit it
Get the source code

The companion repo has the whole policy project ready to build: the archetype output, a template.xml with a guard plus a response-header transform, an annotated config YAML, and the Maven settings for publishing to Exchange. Clone it, set your org ID, and you’re one mvn deploy from your first custom policy.

โ†’ github.com/nestaconnect/mulesoft-from-zero-to-hero
Up next ยท Chapter 16

High Availability & Disaster Recovery โ€” designing integrations that survive a region

Continue reading โ†’