Chapter 13: Quick Reference and Cheat Sheet

A lookup chapter. Use this when you remember the shape of what you need but not the exact syntax: ports, default URLs, CLI flags, XML skeletons, error codes, and common fixes.

Overview

The earlier chapters teach concepts in order; this one is alphabet soup arranged for grep. Bookmark the port and URL tables first, then the deployment.toml block. Everything else slots in around them.

Default Ports

ServiceHTTPHTTPSNotes
Carbon Management Console97639443/carbon
API Gateway (NIO)82808243API traffic
API Publisher Portaln/a9443/publisher
API Developer Portaln/a9443/devportal
API Admin Portaln/a9443/admin
Micro Integrator82908253Integration runtime
MI Management APIn/a9164MI admin operations
Identity Server97639443/carbon
Streaming Integrator90909443Siddhi runtime
JMX RMI11111n/aJVM monitoring
Thrift (Analytics)76117711Event receivers

Port Offset: If running multiple products on one host, set [server] offset in deployment.toml. All ports shift by that offset (e.g., offset=1 makes 9443 become 9444).

[server]
offset = 1

Default Credentials

ComponentUsernamePasswordNotes
Carbon ConsoleadminadminSuper admin
API PublisheradminadminSame as carbon
API DevPortaladminadminSame as carbon
MI Management APIadminadminBasic auth
H2 Database Consolewso2carbonwso2carbonEmbedded DB
Identity ServeradminadminSuper admin

Change admin password (deployment.toml):

[super_admin]
username = "admin"
password = "newStrongPassword123"
create_admin_account = true

Useful URLs

URLPurpose
https://localhost:9443/carbonManagement Console
https://localhost:9443/publisherAPI Publisher
https://localhost:9443/devportalDeveloper Portal
https://localhost:9443/adminAdmin Portal
https://localhost:9164/managementMI Management API
https://localhost:9443/oauth2/tokenOAuth2 Token endpoint
https://localhost:9443/oauth2/authorizeOAuth2 Authorization endpoint
https://localhost:9443/oauth2/revokeOAuth2 Revoke endpoint
https://localhost:9443/oauth2/introspectToken introspection
https://localhost:9443/.well-known/openid-configurationOIDC Discovery
https://localhost:8243/Gateway HTTPS base
http://localhost:8280/Gateway HTTP base

CLI Commands

API Manager CLI (apictl)

# Initialize environment
apictl add env dev --apim https://localhost:9443
apictl add env prod --apim https://prod-apim:9443

# Login
apictl login dev -u admin -p admin
apictl login dev    # interactive prompt

# List APIs
apictl list apis -e dev

# Export an API
apictl export api -n PetStoreAPI -v 1.0.0 -e dev
# Creates: PetStoreAPI_1.0.0.zip

# Import an API
apictl import api -f PetStoreAPI_1.0.0.zip -e prod

# Export/Import all APIs
apictl export apis -e dev --all
apictl import apis -f exported/ -e prod

# Delete an API
apictl delete api -n PetStoreAPI -v 1.0.0 -e dev

# List applications
apictl list apps -e dev -o admin

# API Projects (source-controlled)
apictl init MyAPI --oas https://petstore.swagger.io/v2/swagger.json
apictl import api -f MyAPI/ -e dev

# Get API keys for testing
apictl get keys -n PetStoreAPI -v 1.0.0 -e dev

# Logout
apictl logout dev

Micro Integrator CLI (mi)

# Remote login
mi remote add dev https://localhost:9164
mi remote login dev -u admin -p admin

# Manage artifacts
mi api show -e dev                  # List all APIs
mi api show OrderAPI -e dev         # Show specific API details
mi proxyservice show -e dev         # List proxy services
mi endpoint show -e dev             # List endpoints
mi sequence show -e dev             # List sequences
mi inboundendpoint show -e dev      # List inbound endpoints
mi messagestore show -e dev         # List message stores
mi messageprocessor show -e dev     # List message processors

# Activate/deactivate
mi api activate OrderAPI -e dev
mi api deactivate OrderAPI -e dev
mi messageprocessor activate OrderProcessor -e dev
mi messageprocessor deactivate OrderProcessor -e dev
mi proxyservice activate MyProxy -e dev

# Log levels
mi log-level show org.apache.synapse -e dev
mi log-level update org.apache.synapse DEBUG -e dev

# Data services
mi dataservice show -e dev

# Connectors
mi connector show -e dev

# Users
mi user show -e dev
mi user add newuser newpassword -e dev

Server Commands

# Start servers
./bin/api-manager.sh                   # API Manager
./bin/micro-integrator.sh              # Micro Integrator
./bin/wso2server.sh                    # Identity Server

# Start in background
./bin/api-manager.sh start
./bin/api-manager.sh stop
./bin/api-manager.sh restart

# Start with debug
./bin/api-manager.sh -debug 5005      # Remote debug on port 5005

# Start in OSGi console mode
./bin/api-manager.sh -DosgiConsole

# Check version
./bin/api-manager.sh version

# Clean temp files before start
./bin/api-manager.sh -Dclean

Common XML Configurations

API Definition

<api name="CustomerAPI" context="/customers" xmlns="http://ws.apache.org/ns/synapse">
    <resource methods="GET" uri-template="/{id}">
        <inSequence>
            <call>
                <endpoint>
                    <http method="get" uri-template="http://backend:8080/api/customers/{uri.var.id}"/>
                </endpoint>
            </call>
            <respond/>
        </inSequence>
        <faultSequence>
            <sequence key="commonFaultHandler"/>
        </faultSequence>
    </resource>
    <resource methods="POST">
        <inSequence>
            <call>
                <endpoint>
                    <http method="post" uri-template="http://backend:8080/api/customers"/>
                </endpoint>
            </call>
            <respond/>
        </inSequence>
    </resource>
</api>

Proxy Service

<proxy name="LegacyOrderProxy" startOnLoad="true" transports="http https"
       xmlns="http://ws.apache.org/ns/synapse">
    <target>
        <inSequence>
            <log level="full"/>
            <call>
                <endpoint>
                    <address uri="http://legacy-system:9000/services/OrderService"/>
                </endpoint>
            </call>
            <respond/>
        </inSequence>
        <faultSequence>
            <log level="custom">
                <property name="error" expression="get-property('ERROR_MESSAGE')"/>
            </log>
        </faultSequence>
    </target>
</proxy>

Endpoint Types

<!-- Simple HTTP endpoint -->
<endpoint name="SimpleHTTP" xmlns="http://ws.apache.org/ns/synapse">
    <http method="get" uri-template="http://backend:8080/api/resource"/>
</endpoint>

<!-- Address endpoint (SOAP/REST) -->
<endpoint name="AddressEP" xmlns="http://ws.apache.org/ns/synapse">
    <address uri="http://backend:8080/service">
        <suspendOnFailure>
            <initialDuration>30000</initialDuration>
            <progressionFactor>2</progressionFactor>
            <maximumDuration>120000</maximumDuration>
            <errorCodes>101500,101501,101506,101507,101508</errorCodes>
        </suspendOnFailure>
        <markForSuspension>
            <retriesBeforeSuspension>3</retriesBeforeSuspension>
            <retryDelay>1000</retryDelay>
            <errorCodes>101500,101501</errorCodes>
        </markForSuspension>
        <timeout>
            <duration>30000</duration>
            <responseAction>fault</responseAction>
        </timeout>
    </address>
</endpoint>

<!-- Load Balance endpoint -->
<endpoint name="LoadBalanceEP" xmlns="http://ws.apache.org/ns/synapse">
    <loadbalance algorithm="org.apache.synapse.endpoints.algorithms.RoundRobin">
        <endpoint>
            <address uri="http://backend1:8080/service"/>
        </endpoint>
        <endpoint>
            <address uri="http://backend2:8080/service"/>
        </endpoint>
        <endpoint>
            <address uri="http://backend3:8080/service"/>
        </endpoint>
    </loadbalance>
</endpoint>

<!-- Failover endpoint -->
<endpoint name="FailoverEP" xmlns="http://ws.apache.org/ns/synapse">
    <failover>
        <endpoint>
            <address uri="http://primary:8080/service"/>
        </endpoint>
        <endpoint>
            <address uri="http://secondary:8080/service"/>
        </endpoint>
    </failover>
</endpoint>

Scheduled Task

<task name="CleanupTask"
      class="org.apache.synapse.startup.tasks.MessageInjector"
      group="synapse.simple.quartz"
      xmlns="http://ws.apache.org/ns/synapse">
    <trigger interval="3600"/>    <!-- every hour -->
    <property name="injectTo" value="sequence"/>
    <property name="sequenceName" value="cleanupSequence"/>
    <property name="message">
        <request xmlns="">
            <action>cleanup</action>
        </request>
    </property>
</task>

Data Service

<data name="EmployeeDataService" transports="http https"
      xmlns="http://ws.wso2.org/ns/dataservice">
    <config id="MySQLConnection">
        <property name="driverClassName">com.mysql.cj.jdbc.Driver</property>
        <property name="url">jdbc:mysql://localhost:3306/employees</property>
        <property name="username">db_user</property>
        <property name="password">db_pass</property>
    </config>

    <query id="GetEmployeeQuery" useConfig="MySQLConnection">
        <sql>SELECT id, name, email, department FROM employees WHERE id = :id</sql>
        <param name="id" sqlType="INTEGER" paramType="SCALAR"/>
        <result element="employee" rowName="">
            <element name="id" column="id" xsdType="integer"/>
            <element name="name" column="name" xsdType="string"/>
            <element name="email" column="email" xsdType="string"/>
            <element name="department" column="department" xsdType="string"/>
        </result>
    </query>

    <resource method="GET" path="/employees/{id}">
        <call-query href="GetEmployeeQuery">
            <with-param name="id" query-param="id"/>
        </call-query>
    </resource>
</data>

REST API Calls (curl)

OAuth2 Token Generation

# Client credentials grant
curl -k -X POST https://localhost:9443/oauth2/token \
  -H "Authorization: Basic $(echo -n 'clientId:clientSecret' | base64)" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials"

# Password grant
curl -k -X POST https://localhost:9443/oauth2/token \
  -H "Authorization: Basic $(echo -n 'clientId:clientSecret' | base64)" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=password&username=admin&password=admin"

# Refresh token
curl -k -X POST https://localhost:9443/oauth2/token \
  -H "Authorization: Basic $(echo -n 'clientId:clientSecret' | base64)" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token&refresh_token=<refresh_token>"

# Token introspection
curl -k -X POST https://localhost:9443/oauth2/introspect \
  -H "Authorization: Basic $(echo -n 'admin:admin' | base64)" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "token=<access_token>"

API Manager REST APIs

# Register a client for Admin REST API
curl -k -X POST https://localhost:9443/client-registration/v0.17/register \
  -H "Authorization: Basic $(echo -n 'admin:admin' | base64)" \
  -H "Content-Type: application/json" \
  -d '{
    "callbackUrl": "www.google.lk",
    "clientName": "rest_api_admin",
    "owner": "admin",
    "grantType": "password refresh_token",
    "saasApp": true
  }'

# List all APIs (Publisher)
curl -k -X GET "https://localhost:9443/api/am/publisher/v4/apis" \
  -H "Authorization: Bearer <access_token>"

# Get specific API
curl -k -X GET "https://localhost:9443/api/am/publisher/v4/apis/<api-id>" \
  -H "Authorization: Bearer <access_token>"

# List subscriptions (DevPortal)
curl -k -X GET "https://localhost:9443/api/am/devportal/v3/subscriptions?apiId=<api-id>" \
  -H "Authorization: Bearer <access_token>"

# Create an application (DevPortal)
curl -k -X POST "https://localhost:9443/api/am/devportal/v3/applications" \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "TestApp",
    "throttlingPolicy": "Unlimited",
    "description": "Test application"
  }'

Micro Integrator Management API

MI_URL="https://localhost:9164/management"

# Login and get token
TOKEN=$(curl -sk -X GET "$MI_URL/login" \
  -H "Authorization: Basic $(echo -n 'admin:admin' | base64)" | jq -r '.AccessToken')

# List APIs
curl -sk -X GET "$MI_URL/apis" \
  -H "Authorization: Bearer $TOKEN"

# Get specific API details
curl -sk -X GET "$MI_URL/apis?apiName=OrderAPI" \
  -H "Authorization: Bearer $TOKEN"

# List endpoints
curl -sk -X GET "$MI_URL/endpoints" \
  -H "Authorization: Bearer $TOKEN"

# List sequences
curl -sk -X GET "$MI_URL/sequences" \
  -H "Authorization: Bearer $TOKEN"

# List message stores
curl -sk -X GET "$MI_URL/message-stores" \
  -H "Authorization: Bearer $TOKEN"

# List message processors
curl -sk -X GET "$MI_URL/message-processors" \
  -H "Authorization: Bearer $TOKEN"

# Activate/deactivate message processor
curl -sk -X POST "$MI_URL/message-processors" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "OrderProcessor", "status": "active"}'

# List inbound endpoints
curl -sk -X GET "$MI_URL/inbound-endpoints" \
  -H "Authorization: Bearer $TOKEN"

# Get server logs
curl -sk -X GET "$MI_URL/logs?file=wso2carbon" \
  -H "Authorization: Bearer $TOKEN"

# Update log level
curl -sk -X PATCH "$MI_URL/logging" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"loggerName": "org.apache.synapse", "loggingLevel": "DEBUG"}'

deployment.toml Quick Reference

# ─── Server ───────────────────────────────
[server]
hostname = "apim.example.com"
offset = 0

[super_admin]
username = "admin"
password = "admin"
create_admin_account = true

# ─── Database ─────────────────────────────
[database.apim_db]
type = "mysql"
url = "jdbc:mysql://db-host:3306/apim_db?useSSL=false"
username = "apim_user"
password = "apim_pass"
driver = "com.mysql.cj.jdbc.Driver"

[database.apim_db.pool_options]
maxActive = 50
maxWait = 60000
testOnBorrow = true
validationQuery = "SELECT 1"
validationInterval = 30000

[database.shared_db]
type = "mysql"
url = "jdbc:mysql://db-host:3306/shared_db?useSSL=false"
username = "shared_user"
password = "shared_pass"
driver = "com.mysql.cj.jdbc.Driver"

# ─── Keystore ─────────────────────────────
[keystore.primary]
file_name = "wso2carbon.jks"
password = "wso2carbon"
alias = "wso2carbon"
key_password = "wso2carbon"

[keystore.tls]
file_name = "server.jks"
password = "changeit"
alias = "server"
key_password = "changeit"

[truststore]
file_name = "client-truststore.jks"
password = "wso2carbon"

# ─── Gateway ──────────────────────────────
[[apim.gateway.environment]]
name = "Production"
type = "production"
service_url = "https://gateway:9443/services/"
ws_endpoint = "ws://gateway:9099"
wss_endpoint = "wss://gateway:8099"
http_endpoint = "http://gateway:8280"
https_endpoint = "https://gateway:8243"

# ─── Traffic Manager ─────────────────────
[apim.throttling]
enable_data_publishing = true
service_url = "https://traffic-manager:9443/services/"
throttle_decision_endpoints = ["tcp://traffic-manager:5672"]

# ─── CORS ─────────────────────────────────
[apim.cors]
allow_origins = "*"
allow_methods = ["GET", "PUT", "POST", "DELETE", "PATCH", "OPTIONS"]
allow_headers = ["Authorization", "Content-Type", "X-Requested-With"]
allow_credentials = false

# ─── JWT ──────────────────────────────────
[apim.jwt]
enable = true
encoding = "base64"
header = "X-JWT-Assertion"
claims_extractor_impl = "org.wso2.carbon.apimgt.impl.token.DefaultClaimsRetriever"

# ─── Caching ──────────────────────────────
[apim.cache.gateway_token]
enable = true
expiry_time = "900s"

[apim.cache.resource]
enable = true
expiry_time = "900s"

# ─── Analytics ────────────────────────────
[apim.analytics]
enable = true
type = "elk"

[apim.analytics.elk]
host = "elasticsearch:9200"

Error Codes

Transport Error Codes

CodeMeaningCommon Cause
101000Receiver I/O errorBackend refused connection
101001Receiver I/O timeoutBackend too slow to accept
101500Sender I/O errorCannot write to backend
101501Sender I/O timeoutBackend didn't respond in time
101503Connection failedDNS or network issue
101504Connection timed outFirewall or backend down
101505Connection closedBackend dropped connection
101506Protocol violationMalformed HTTP response
101507Connect cancelConnection attempt cancelled
101508Connect timeoutTCP handshake timeout
101509Send abortSend operation aborted

Synapse Error Codes

CodeMeaningCommon Cause
0Unexpected errorUnclassified
303000Failure sending using PTPassthrough transport send failure
303001Connecting to backendBackend unreachable
303100Connection timeoutResponse waited too long
304000Receiving responseMalformed response from backend

HTTP Status Codes in Mediation

<!-- Read the backend's HTTP status code -->
<property name="backendStatus" expression="$axis2:HTTP_SC"/>

<!-- Set a specific HTTP status code for the response -->
<property name="HTTP_SC" value="201" scope="axis2"/>

<!-- Common status codes to set -->
<!-- 200 OK (default) | 201 Created | 202 Accepted | 204 No Content -->
<!-- 400 Bad Request  | 401 Unauthorized | 403 Forbidden | 404 Not Found -->
<!-- 500 Internal Error | 502 Bad Gateway | 503 Service Unavailable -->

Troubleshooting

Server Won't Start

# Check port conflicts
netstat -tlnp | grep -E '(9443|8280|8243)'

# Check Java version (requires JDK 11 or 17)
java -version

# Check JAVA_HOME
echo $JAVA_HOME

# Review startup log
tail -200 repository/logs/wso2carbon.log

# Check for lock files
ls -la repository/components/default/configuration/org.eclipse.equinox.simpleconfigurator/.lock

# Clean and restart
rm -rf repository/deployment/server/webapps/  # will be regenerated
./bin/api-manager.sh -Dclean

API Returns 401 Unauthorized

# Check if token is valid
curl -k -X POST https://localhost:9443/oauth2/introspect \
  -H "Authorization: Basic $(echo -n 'admin:admin' | base64)" \
  -d "token=<your_token>"

# Check if API is published (not just CREATED)
apictl list apis -e dev

# Verify subscription exists
apictl list api-products -e dev

# Check token type matches (API key vs OAuth2 vs JWT)
# Ensure Authorization header format: "Bearer <token>"

Backend Connection Failures

# Test backend connectivity from WSO2 host
curl -v http://backend-host:8080/health

# Check DNS resolution
nslookup backend-host

# Enable wire logs temporarily
# In deployment.toml:
# [[logging.loggers]]
# name = "org.apache.synapse.transport.http.wire"
# level = "DEBUG"

# Check endpoint status via MI CLI
mi endpoint show BackendEndpoint -e dev

High Memory Usage

# Check current heap settings
ps aux | grep wso2 | grep -o 'Xm[sx][^ ]*'

# Tune JVM in bin/api-manager.sh or bin/micro-integrator.sh
# -Xms512m -Xmx2048m    (min/max heap)
# -XX:MaxMetaspaceSize=512m

# Take a heap dump for analysis
jmap -dump:format=b,file=heap.hprof <PID>

# Take a thread dump
jstack <PID> > threads.txt

# Monitor GC
tail -f repository/logs/gc.log

Message Transformation Failures

<!-- Debug: Log the full message at each step -->
<log level="full"/>

<!-- Debug: Log specific expressions -->
<log level="custom">
    <property name="debug-payload" expression="json-eval($)"/>
    <property name="debug-status" expression="$axis2:HTTP_SC"/>
    <property name="debug-content-type" expression="get-property('ContentType')"/>
</log>

<!-- Common issue: wrong content type -->
<property name="messageType" value="application/json" scope="axis2"/>
<property name="ContentType" value="application/json" scope="axis2"/>

<!-- Common issue: empty body after call mediator -->
<!-- Ensure the backend returns a body; check for 204 No Content -->

File System Layout

wso2am-4.2.0/
├── bin/                          # Startup scripts
│   ├── api-manager.sh            # Main startup
│   ├── micro-integrator.sh       # MI startup
│   └── ciphertool.sh             # Password encryption
├── repository/
│   ├── conf/
│   │   └── deployment.toml       # Main configuration
│   ├── deployment/
│   │   └── server/
│   │       ├── synapse-configs/  # Mediation artifacts
│   │       │   └── default/
│   │       │       ├── api/      # API definitions
│   │       │       ├── endpoints/
│   │       │       ├── sequences/
│   │       │       ├── proxy-services/
│   │       │       └── tasks/
│   │       ├── carbonapps/       # Deployable CARs
│   │       └── webapps/          # Web applications
│   ├── components/
│   │   ├── lib/                  # Third-party JARs (JDBC, etc.)
│   │   └── dropins/              # OSGi bundles
│   ├── database/                 # Embedded H2 databases
│   ├── logs/                     # All log files
│   └── resources/
│       └── security/
│           ├── wso2carbon.jks    # Primary keystore
│           └── client-truststore.jks
├── docker-compose.yml            # Docker deployment (if bundled)
└── updates/                      # WSO2 Updates metadata

Expression Quick Reference

JSON Path Expressions

ExpressionDescription
json-eval($.name)Root-level field
json-eval($.user.address.city)Nested field
json-eval($.items[0])First array element
json-eval($.items[*].name)All names from array
json-eval($.items.length())Array length

XPath Expressions

ExpressionDescription
//elementSelect element anywhere
//element/@attrSelect attribute
//ns:elementNamespace-qualified element
//element[1]First matching element
//element[last()]Last matching element
count(//item)Count of elements

Property Access

ExpressionDescription
$ctx:propertyNameDefault (synapse) scope
$trp:headerNameTransport header
$axis2:propertyNameAxis2 scope
get-property('name')Default scope
get-property('transport', 'name')Transport scope
get-property('axis2', 'name')Axis2 scope
get-property('operation', 'name')Operation scope
get-property('registry', 'path')Registry resource
get-property('system', 'key')Java system property
get-property('SYSTEM_TIME')Current timestamp
get-property('MESSAGE_ID')Message UUID

URI Template Variables

PatternIn EndpointAccess
/{id} in resource{uri.var.id}get-property('uri.var.id')
?name=val query paramn/aget-property('query.param.name')

Docker Quick Start

# docker-compose.yml: minimal WSO2 APIM + MI
version: '3.8'
services:
  apim:
    image: wso2/wso2am:4.2.0
    ports:
      - "9443:9443"
      - "8280:8280"
      - "8243:8243"
    volumes:
      - ./conf/deployment.toml:/home/wso2carbon/wso2am-4.2.0/repository/conf/deployment.toml
    healthcheck:
      test: ["CMD", "curl", "-k", "https://localhost:9443/carbon/admin/login.jsp"]
      interval: 30s
      timeout: 10s
      retries: 5

  mi:
    image: wso2/wso2mi:4.2.0
    ports:
      - "8290:8290"
      - "8253:8253"
      - "9164:9164"
    volumes:
      - ./carbonapps:/home/wso2carbon/wso2mi-4.2.0/repository/deployment/server/carbonapps
    depends_on:
      apim:
        condition: service_healthy
# Build and deploy a CAPP from Integration Studio
# 1. Export CompositeExporter as .car file
# 2. Copy to carbonapps volume
cp MyIntegration_1.0.0.car ./carbonapps/

# MI hot-deploys automatically; verify:
curl -sk https://localhost:9164/management/apis \
  -H "Authorization: Basic $(echo -n 'admin:admin' | base64)"

Common Patterns Cheat Sheet

I want to...Use
Transform JSON payload<payloadFactory media-type="json">
Transform XML payload<payloadFactory media-type="xml"> or <xslt>
Route by content<switch source="json-eval($.field)">
Route by header<filter source="get-property('transport','X-Type')">
Call backend and continue<call> (non-blocking)
Call backend and wait<callout> (blocking)
Fan out to N backends<clone> with N <target> blocks
Split array, process each<iterate expression="json-eval($.items)">
Merge parallel results<aggregate> after <clone>
Async fire-and-forget<property name="OUT_ONLY" value="true"/> + <call>
Queue for guaranteed delivery<store messageStore="MyStore"/>
Set response status code<property name="HTTP_SC" value="201" scope="axis2"/>
Add response header<property name="X-Custom" value="val" scope="transport"/>
Log for debugging<log level="full"/> or <log level="custom">
Handle errors<faultSequence> with get-property('ERROR_MESSAGE')
Schedule a recurring job<task> with <trigger interval="N"/>
Expose a database as RESTData Service (.dbs artifact)
Validate JSON schema<validate> with JSON Schema resource

Key Takeaways

  • Bookmark the port and URL tables: you will reference them constantly
  • Use apictl for API lifecycle and mi CLI for integration artifact management
  • The MI Management REST API provides programmatic access to everything the CLI can do
  • deployment.toml is the single configuration file for all product settings
  • Transport error codes (101xxx) indicate network-level issues; Synapse codes (303xxx/304xxx) indicate mediation issues
  • Wire logs are your best friend for debugging but must be disabled in production
  • Expression syntax (json-eval, XPath, property access) is the foundation of all mediation logic

Where to Go From Here

You have read enough WSO2 to start building real things. Pick the path that matches your role:

  • API platform owner: stand up an API Manager cluster behind a load balancer, integrate it with WSO2 Identity Server, and put apictl in a CI pipeline so APIs flow from dev to production through Git.
  • Integration developer: build a Composite Application of three or four real APIs with mediation, deploy it to Micro Integrator on Kubernetes, and wire correlation logging through to Grafana.
  • Identity engineer: federate Identity Server with at least one external IdP (Google, Azure AD, or Okta), enable adaptive MFA based on risk, and write a custom authenticator script.

External resources worth bookmarking:

When something breaks in production: read the correlation log first, the wire log second, and the JVM stats third. The fix is almost always somewhere in the first three minutes of those.