Policy Integrations
Policy integrations connect policy checks to
external providers.
policy-integration runs inside
every MPC node and performs the
provider HTTP calls.
| Term | Meaning |
|---|---|
| External provider registry | Private MPC-node configuration that maps each integration and operation to its endpoint and payload projection |
| Public integration catalog | Public view clients use to discover integration IDs, operations, and descriptions; endpoints are excluded |
| Payload projection | List of transaction and client-context fields included in a provider request |
| Provider protocol | JSON request and response exchanged with the provider |
policy-integration resolves the registry entry, builds the projected request,
calls the provider, and returns pass, fail, or unavailable to the policy
engine.
External provider registry
Set EXTERNAL_PROVIDER_REGISTRY to the same logical integrations and
operations on every MPC node:
export EXTERNAL_PROVIDER_REGISTRY='[
{
"integration_id": "transaction-screening",
"endpoint": "https://screening.example.com/v1/policy/check",
"operations": [
{
"operation": "screen-ethereum-destination",
"description": "Screen an Ethereum transfer destination for compliance risk",
"payload_projection": {
"transaction": ["/requestType", "/to", "/data"]
}
}
]
}
]'
The complete JSON array is deserialized as RegistryConfig struct which contains multiple integrations. Each integration is defined like below.
| Field | Description |
|---|---|
integration_id | Logical provider identifier referenced by policies |
endpoint | Private HTTP endpoint called by policy-integration |
operations | Operations enabled for this integration |
operation | Identifier defined by the provider and selected by policies |
description | Description published in the integration catalog |
payload_projection | Configured by the deployment operator to specify which transaction and client-context fields policy-integration includes in the provider request |
Policies reference only integration_id and operation. Each MPC node
resolves and validates them through its local registry.
The provider must implement the same operation identifiers.
All MPC nodes must expose the same logical integrations and operations. A catalog mismatch causes inconsistent capability list and prevents policy authors to create robust policies.
Public integration catalog
Client applications discover available capabilities through the public GET endpoint:
curl -X GET "http://<YOUR_WALLET_BACKEND_ENDPOINT>/v2/rest/getPolicyIntegrations"
The catalog includes integration IDs, operations, descriptions, and payload projections. It never exposes provider endpoints or credentials.
The deployment operator defines integration_id
and operation. The policy author selects them from the catalog and creates the
policy-local check_id.
Payload projection
payload_projection controls the transaction and context fields disclosed to
the provider:
{
"payload_projection": {
"transaction": ["/to", "/value"],
"context": ["/subject/id"]
}
}
A provider request always includes version, evaluation_id, and
operation and can contain two projected sections:
transaction: selects fields from the JSON representation of the transaction being evaluated.context: selects/subject/idfrom the authenticatedpolicy_integration_contextsupplied by the client.
The transaction is extracted from the signing request and converted into JSON
before policy-integration applies the projection.
The available transaction fields depend on requestType:
EIP1559:from,to,chainId,nonce,value,data, and gas fields.EIP712:domain,types,primaryType, andmessage.EIP191:message.rawBytes:data.solanaTransaction: serialized Solana message fields such asaccountKeysandinstructions.
policy-integration selects JSON fields only; it does not decode contract
calldata or interpret transaction instructions. The provider performs
operation-specific decoding.
The selections use RFC 6901 JSON Pointers. Unselected fields are omitted, and a missing selected field fails the check before an HTTP request is made.
Provider protocol
For each external check, policy-integration resolves the configured endpoint
and projection, sends a ProviderRequest, and waits for the provider decision.
Request
policy-integration sends an HTTP POST to the integration's configured
endpoint:
POST <endpoint>
Content-Type: application/json
X-SL-Policy-External-Check-Version: 1
It constructs the JSON body from the policy check and the projected transaction or context:
{
"version": "1",
"evaluation_id": "5d10...",
"operation": "screen-context-address",
"context": {
"address": "0x1234..."
}
}
| Field | Required | Usage |
|---|---|---|
version | Yes | JSON schema version set by policy-integration |
evaluation_id | Yes | Opaque identifier generated for this check |
operation | Yes | Operation selected by the policy |
transaction | When projected | Fields extracted from the transaction being evaluated |
context | When projected | Fields extracted from the client's policy_integration_context |
X-SL-Policy-External-Check-Version identifies the HTTP protocol used between
policy-integration and the provider. The body version identifies the JSON
schema of ProviderRequest.
The provider routes by operation and validates the projected payload.
Expected response
The provider returns HTTP 200 with a JSON decision:
{
"evaluation_id": "5d10...",
"result": "pass",
"reason_code": "screening_clear"
}
| Field | Required | Usage |
|---|---|---|
evaluation_id | Yes | Must equal the request evaluation_id |
result | Yes | Provider decision: pass or fail |
reason_code | No | Stable code describing a failed decision |
policy-integration validates the status, response schema, evaluation ID, and
decision. Timeout, non-success status, or invalid response will fail the Rule evaluation.
Provider example
In dummy-kyc-provider example, there are 3 specific operations:
- screen-context-address
- screen-ethereum-destination
- screen-solana-destinations
Run it locally:
cargo run -p dummy-kyc-provider
The service listens on http://127.0.0.1:4010. Its web interface lets you add or remove restricted addresses.
Register the dummy-kyc integration in EXTERNAL_PROVIDER_REGISTRY on each MPC node:
[
{
"integration_id": "dummy-kyc",
"endpoint": "http://127.0.0.1:4010/v1/policy/check",
"operations": [
{
"operation": "screen-context-address",
"description": "Screen a client-supplied address for compliance risk",
"payload_projection": {
"context": ["/address"]
}
},
{
"operation": "screen-ethereum-destination",
"description": "Screen an Ethereum transfer destination for compliance risk",
"payload_projection": {
"transaction": ["/requestType", "/to", "/data"]
}
},
{
"operation": "screen-solana-destinations",
"description": "Screen Solana transfer destinations for compliance risk",
"payload_projection": {
"transaction": [
"/requestType",
"/accountKeys",
"/instructions"
]
}
}
]
}
]
Each payload_projection above drives what policy-integration extracts from
the signing request and forwards to the provider. The examples below trace that
for each operation: signing request, projection applied, and resulting provider
request body.
screen-context-address
payload_projection selects /address from the client-supplied
policy_integration_context.
Signing request (client → MPC node):
{
"policy_integration_context": "{\"address\":\"0x1234...\"}"
}
Payload projection (registry config):
{
"context": ["/address"]
}
Provider request body (policy-integration → provider):
{
"version": "1",
"evaluation_id": "5d10...",
"operation": "screen-context-address",
"context": {
"address": "0x1234..."
}
}
dummy-kyc-provider receives this request and screens the address against its restricted list.
screen-ethereum-destination
payload_projection selects /requestType, /to, and /data from the
decoded EIP-1559 transaction.
Signing request (client → MPC node):
{
"requestType": "EIP1559",
"signingMessage": "{\"to\":\"0x1234...\",\"value\":\"0x1\",\"data\":\"0x\"}"
}
Payload projection (registry config):
{
"transaction": ["/requestType", "/to", "/data"]
}
Provider request body (policy-integration → provider):
{
"version": "1",
"evaluation_id": "5d10...",
"operation": "screen-ethereum-destination",
"transaction": {
"requestType": "EIP1559",
"to": "0x1234...",
"data": "0x"
}
}
dummy-kyc-provider receives this request and screens to for native ETH transfers or the recipient encoded in data for ERC-20 transfers.
screen-solana-destinations
payload_projection selects /requestType, /accountKeys, and /instructions
from the decoded Solana transaction.
Signing request (client → MPC node):
{
"requestType": "solanaTransaction",
"signingMessage": "<hex-encoded-msg>"
}
Payload projection (registry config):
{
"transaction": ["/requestType", "/accountKeys", "/instructions"]
}
Provider request body (policy-integration → provider):
{
"version": "1",
"evaluation_id": "5d10...",
"operation": "screen-solana-destinations",
"transaction": {
"requestType": "solanaTransaction",
"accountKeys": ["<fee-payer>", "<recipient>", "TokenkegQfe..."],
"instructions": [{ "programIdIndex": 2, "accounts": [0, 1], "data": "..." }]
}
}
dummy-kyc-provider receives this request and screens the recipient account for native SOL transfers and the destination token account for SPL transfers.
Provider decision
All three operations return the same response shape:
| Address status | Result | Reason code |
|---|---|---|
| Not restricted | pass | None |
| Restricted | fail | address_blacklisted |