Skip to main content
External calls require a synchronizer running protocol version 36 or later and a Daml package targeting LF 2.4 or later.
This page covers the practical side of external calls: a worked example, the participant configuration, and the externalCall function. For how calls travel through the transaction and what the participants verify, see External Calls.

A Worked Example

Suppose the parties of a workflow want transactions to record an instrument price attested by a price oracle that each participant operator runs as an extension service. Run the oracle as a sidecar on the same machine as Canton. The examples below assume the participant can reach the service at the loopback address 127.0.0.1. Each participant that submits or confirms these transactions configures the oracle under the same extension identifier, here price-oracle:
The Daml choice requests the call with externalCall:
When FetchPrice is exercised, the submitting participant sends the configuration and input payloads to its price-oracle service, records the returned price in the transaction, and the choice returns it as a hex-encoded byte string. At confirmation time, the participants hosting the checking parties re-execute the same call against their own price-oracle service and approve only if the outputs match.

Configuring an Extension Service

Extension services are configured per participant under canton.participants.<participant>.parameters.engine.extensions, keyed by the extension identifier that Daml code passes to externalCall:
Notable parameters (see the scaladoc of ExtensionServiceConfig for the full reference):
  • address, port, version: the endpoint of the extension service’s HTTP API.
  • tls: enable TLS towards the service, with tls.trust-collection-file naming the trust anchors.
  • auth: optional bearer-token authentication (type = bearer-token-file with token-file); the token is never logged.
  • connect-timeout, request-timeout, max-retries, retry-initial-delay, retry-max-delay: connection handling; retries apply per logical call.
  • max-response-body-bytes: upper bound on accepted service responses.
  • validate-on-startup: probe the service’s version endpoint when the participant starts.

The externalCall Function

The function is provided by the Daml standard library module DA.ExternalCall:
externalCall extensionId functionId config input requests a call to function functionId of the extension configured on the participant under extensionId. The config argument is the extension configuration hash — the value the parties use to pin the service configuration they agreed on, as in the example above — and input is the call input; both are hex-encoded byte strings, and the empty string represents zero bytes. Payloads are canonicalized to lowercase before execution, so two calls that differ only in hex casing are the same call. The result is the service response, again as a hex-encoded byte string. Malformed payloads, missing extension configuration, extension-service failures, and invalid service output fail the update; runtime and service errors include the extension and function context.

Next Steps

  • External Calls — How calls travel through the transaction: the flow, validation, and the trust model.
  • Error Codes Reference — The external-call validation error codes carry explanations and resolutions generated from the participant sources.