Skip to main content
Version: 5.1

ICP Runtime API

The Integration Control Plane (ICP) exposes a dedicated REST service for runtime agents (Micro Integrator and Ballerina Integrator) to register themselves and continuously report their state. The ICP uses the data from this service to drive reconciliation — pushing control commands back to runtimes to align their state with the desired configuration.

This API is consumed by runtime agents, not by end users. It is separate from the Management API (GraphQL) and the Authentication API (user-facing REST).

Base URL​

https://<icp-host>:9445/icp

The default runtime listener port is 9445.


Authentication​

All requests must include a signed JWT in the Authorization header:

Authorization: Bearer <runtime-jwt>

The token is validated using kid-based lookup:

  1. The JWT header must contain a kid claim identifying the org secret key.
  2. The ICP looks up the HMAC secret associated with that kid.
  3. The JWT is validated against that secret with:
    • Issuer: icp-runtime-jwt-issuer
    • Audience: icp-server
    • Required scope claim: runtime_agent
    • Clock skew tolerance: 10 seconds

The ICP does not issue runtime tokens. The runtime signs its own token with an org secret, which you generate in the ICP console or with the createOrgSecret mutation of the Management API. The secret has the form <keyId>.<keyMaterial>. Sign the JWT with HS256, using keyMaterial as the HMAC key, and set:

  • kid in the JWT header to keyId
  • iss to icp-runtime-jwt-issuer, aud to icp-server, and scope to runtime_agent in the payload

The ICP runtime bridge does this for you from the secret in its configuration. A key can be unbound (not yet associated with a project/component) or bound.


Endpoints​

POST /icp/heartbeat​

Submits a full heartbeat from a runtime. This is the primary registration and state-reporting mechanism. On the first heartbeat from an unbound key, the ICP auto-provisions the project and component and binds the key to them.

After processing the heartbeat, the ICP runs reconciliation and returns any pending control commands for the runtime to execute.

Request body:

{
"heartbeatVersion": "v1.0",
"runtimeId": "3f2b8c1e-6d4a-4e9b-9a71-0c5d2e8f4b10",
"runtimeType": "MI",
"status": "RUNNING",
"environment": "dev",
"project": "MyProject",
"component": "OrderService",
"version": "1.0.0",
"runtimeHostname": "mi-host.example.com",
"runtimePort": "9164",
"nodeInfo": {
"platformName": "wso2-mi",
"platformVersion": "4.3.0",
"osName": "Linux",
"osVersion": "5.15.0",
"osArch": "amd64",
"javaVersion": "17.0.9",
"javaVendor": "Eclipse Adoptium",
"totalMemory": 2147483648,
"freeMemory": 1073741824,
"maxMemory": 2147483648,
"usedMemory": 1073741824
},
"artifacts": {
"listeners": [],
"services": [],
"apis": [{ "name": "OrderAPI", "context": "/orders", "state": "enabled" }],
"proxyServices": [],
"sequences": [],
"tasks": [],
"templates": [],
"messageStores": [],
"messageProcessors": [],
"localEntries": [],
"dataServices": [],
"carbonApps": [],
"dataSources": [],
"connectors": [],
"registryResources": [],
"endpoints": [],
"inboundEndpoints": []
},
"runtimeHash": "sha256-abc123...",
"timestamp": [1746093600, 0]
}

Request fields:

FieldTypeRequiredDescription
heartbeatVersionstringNoHeartbeat format version. Default: "v1.0"
runtimeIdstringYesUnique identifier for this runtime instance, as a 36-character UUID
runtimeTypestringYes"MI" or "BI"
statusstringYesCurrent runtime status ("RUNNING"). The ICP marks the runtime OFFLINE when its heartbeats stop
environmentstringYesHandler of the environment the runtime belongs to. It must match the environment of the key
projectstringYesProject name. For an unbound key, it is converted to a handler (for example, MyProject becomes myproject) and the project is created if it does not exist. For a bound key, the bound project is used
componentstringYesComponent/integration name, handled the same way as project
versionstringNoRuntime version
runtimeHostnamestringNoHostname of the MI management API
runtimePortstringNoPort of the MI management API
nodeInfoobjectYesHost system information (see below)
artifactsobjectYesAll deployed artifacts grouped by type (see below)
runtimeHashstringYesHash of the full runtime state, used for delta comparison
timestamparrayYesUTC time of the heartbeat as [epochSeconds, fractionOfSecond], for example [1746093600, 0]
logLevelsobjectNoCurrent log levels as a { "loggerName": "LEVEL" } map (Ballerina runtimes)

nodeInfo fields:

FieldTypeDescription
platformNamestringPlatform identifier (default: "wso2-mi")
platformVersionstringPlatform/product version
platformHomestringInstallation directory
ballerinaHomestringBallerina home directory (default profile runtimes)
osNamestringOperating system name
osVersionstringOS version
osArchstringCPU architecture
javaVersionstringJVM version
javaVendorstringJVM vendor
carbonHomestringCarbon home directory (MI runtimes)
totalMemoryintegerTotal JVM heap memory in bytes
freeMemoryintegerFree JVM heap memory in bytes
maxMemoryintegerMaximum JVM heap memory in bytes
usedMemoryintegerUsed JVM heap memory in bytes

artifacts fields:

FieldTypeDescription
listenersarrayActive HTTP/HTTPS listeners (default profile)
servicesarrayDeployed Ballerina services (default profile)
mainobjectMain Ballerina package info: packageOrg, packageName, packageVersion (default profile)
apisarrayREST APIs (MI)
proxyServicesarrayProxy services (MI)
sequencesarraySequences (MI)
tasksarrayScheduled tasks (MI)
templatesarrayTemplates (MI)
messageStoresarrayMessage stores (MI)
messageProcessorsarrayMessage processors (MI)
localEntriesarrayLocal entries (MI)
dataServicesarrayData services (MI)
carbonAppsarrayCarbon applications (MI)
dataSourcesarrayData sources (MI)
connectorsarrayConnectors (MI)
registryResourcesarrayRegistry resources (MI)
endpointsarrayNamed endpoints (MI)
inboundEndpointsarrayInbound endpoints (MI)

Each artifact entry includes a name field and, optionally, a state field ("enabled" or "disabled"). Some types need more fields; for example, apis entries also need a context.

Response 201 Created:

{
"acknowledged": true,
"fullHeartbeatRequired": false,
"commands": [
{
"commandId": "01f1c859-4034-1260-b29d-9b94be3f8329",
"runtimeId": "3f2b8c1e-6d4a-4e9b-9a71-0c5d2e8f4b10",
"targetArtifact": { "name": "httpListener", "package": "" },
"action": "STOP",
"issuedAt": [1792042108, 0.4409251],
"status": "PENDING",
"signature": "rzY2WwZEWSayUSGWFjy1OS3wUbXR1NElZvCykgyIoX4="
}
],
"errors": []
}
FieldTypeDescription
acknowledgedbooleantrue if the heartbeat was accepted and processed. If processing fails, the response is still 201 with acknowledged: false and the reason in errors
fullHeartbeatRequiredbooleanIf true, the runtime must send a full heartbeat on the next cycle
commandsarrayControl commands to execute (may be empty)
errorsarrayError messages if processing failed

commands entry fields:

FieldTypeDescription
commandIdstringUnique command identifier
runtimeIdstringTarget runtime
targetArtifact.namestringName of the artifact to act on
targetArtifact.packagestringPackage of the artifact, if any
actionstringSTART, STOP, SET_LOGGER_LEVEL, WORKFLOW_MGMT, or MI_MGMT
issuedAtarrayUTC time as [epochSeconds, fractionOfSecond]
statusstringPENDING, SENT, ACKNOWLEDGED, FAILED, or COMPLETED
payloadstringJSON-encoded additional data for the action (e.g., log level settings)
signaturestringBase64 HMAC-SHA256 signature of the command, keyed with the org secret, so the runtime can verify that the command came from the ICP

Error responses:

StatusReason
400 Bad RequestInvalid heartbeat payload (for example, a runtimeId that is not a UUID or a heartbeatVersion other than v1.0), unknown kid, or invalid project/component name
401 UnauthorizedMissing or invalid JWT, or insufficient scope (requires runtime_agent)
409 ConflictEnvironment or runtime type mismatch between the JWT key binding and the heartbeat

POST /icp/deltaHeartbeat​

Submits a lightweight delta heartbeat containing only the runtime ID and a hash of its current state. If the hash matches the ICP's last known state, no full resync is needed, reducing overhead for stable runtimes.

If the key is unbound (not yet associated with a project/component), the ICP cannot resolve the context from a delta heartbeat alone. It returns acknowledged: false and fullHeartbeatRequired: true to instruct the runtime to send a full heartbeat.

Request body:

{
"heartbeatVersion": "v1.0",
"runtimeId": "3f2b8c1e-6d4a-4e9b-9a71-0c5d2e8f4b10",
"runtimeHash": "sha256-abc123...",
"timestamp": [1746093900, 0]
}
FieldTypeRequiredDescription
heartbeatVersionstringNoHeartbeat format version. Default: "v1.0"
runtimeIdstringYesUnique identifier for this runtime instance
runtimeHashstringYesHash of the full runtime state
timestamparrayYesUTC time as [epochSeconds, fractionOfSecond]

Response 201 Created:

Same structure as the full heartbeat response. If fullHeartbeatRequired is true, the runtime must send a POST /icp/heartbeat on the next cycle.

{
"acknowledged": true,
"fullHeartbeatRequired": false,
"commands": [],
"errors": []
}

Error responses:

StatusReason
400 Bad RequestUnknown kid
401 UnauthorizedMissing or invalid JWT
409 ConflictRuntime type mismatch