Skip to main content

Policy Integrations

Policy integrations connect policy checks to external providers. policy-integration runs inside every MPC node and performs the provider HTTP calls.

TermMeaning
External provider registryPrivate MPC-node configuration that maps each integration and operation to its endpoint and payload projection
Public integration catalogPublic view clients use to discover integration IDs, operations, and descriptions; endpoints are excluded
Payload projectionList of transaction and client-context fields included in a provider request
Provider protocolJSON 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.

FieldDescription
integration_idLogical provider identifier referenced by policies
endpointPrivate HTTP endpoint called by policy-integration
operationsOperations enabled for this integration
operationIdentifier defined by the provider and selected by policies
descriptionDescription published in the integration catalog
payload_projectionConfigured 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/id from the authenticated policy_integration_context supplied 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, and message.
  • EIP191: message.
  • rawBytes: data.
  • solanaTransaction: serialized Solana message fields such as accountKeys and instructions.

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..."
}
}
FieldRequiredUsage
versionYesJSON schema version set by policy-integration
evaluation_idYesOpaque identifier generated for this check
operationYesOperation selected by the policy
transactionWhen projectedFields extracted from the transaction being evaluated
contextWhen projectedFields 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"
}
FieldRequiredUsage
evaluation_idYesMust equal the request evaluation_id
resultYesProvider decision: pass or fail
reason_codeNoStable 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 statusResultReason code
Not restrictedpassNone
Restrictedfailaddress_blacklisted