Open in ClaudeOpen in ChatGPT

API_CALL

API_CALL(url, ['inputNodes'], ["resultLevels"] [, format, version, message, timeout])

In Data access

This function requires a separate subscription and is not available in all Valsight instances.

The API_CALL function sends node values to an external service over an HTTP POST request and returns the service’s response to the model as a node.

Use this function when a calculation must run on an external system and the result should flow back into the model: API_CALL("https://example.com/sum", ['Node A', 'Node B'], ["Year", "Country"]).

If you are implementing the receiving service, see Build a service for API_CALL for a worked example.

Parameters

urlStringRequired
The endpoint the POST request is sent to. Must match the allow-list configured by an administrator (see Availability & limits).
inputNodesList of node referencesRequired
List of nodes, in square brackets, whose values are sent with the request.
resultLevelsList of level namesRequired
List of levels, in square brackets, that Valsight expects back from the service. These define the shape of the returned node.
formatStringOptional
Data format of the response. Only JSON is supported. Default: JSON.
versionStringOptional
Version identifier sent with the request. Passed through untouched.
messageStringOptional
Free-text message sent with the request. Passed through untouched.
timeoutNumberOptional
Time limit for the call, in seconds. If the service does not respond in time, the request is cancelled. Default: 30.

The four optional arguments are positional and nested: to pass timeout you must also pass format, version and message before it. There is no way to skip an earlier one.

Output shape

Dimensionality
Per dimension, the deepest level listed in resultLevels. Listing both Year and Quarter produces a node on Quarter alone.
Values
Taken from the service’s response, parsed from the Valsight Table JSON payload.
Row count
Determined by the rows the service returns.

The response is validated against every level named in resultLevels, in the order written, even where the node itself ends up on fewer levels.

Watch out

  • The response must follow the Valsight Table JSON structure, otherwise it cannot be converted into a node. See Response format.
  • The HTTP status must be in the 200–299 range. On anything else Valsight discards the body, so a message the service put in error_message never reaches the user. Report a business error as HTTP 200 with response_status set to ERROR instead.
  • Input nodes are sent with full dimensionality. A node dimensioned on Month alone arrives at the service carrying its Year and Quarter columns too. This is the only channel through which dimensionality is communicated, so a service should read the levels it needs by name and ignore the rest.
  • Every value in rowData is a string, numbers included. The service has to convert them.
  • Unknown keys in the response are ignored; only response_status, error_message and output are read.
  • If response_status is ERROR, Valsight surfaces the text in error_message and returns no data.
  • A node is recalculated on every user interaction. A service that takes seconds to answer makes the model feel unresponsive well before the timeout is reached.

Availability & limits

API_CALL is off by default and is controlled by global feature flags that an administrator configures:

  • featureFlags.apiCall.allowedUrlsRegex: a Java regular expression of permitted URLs. Empty by default, which allows no URLs, so an administrator must set it before the function can be used.
  • featureFlags.apiCall.maxRowsToSend: maximum combined number of rows across all input nodes per request. Default 150000.
  • featureFlags.apiCall.maxMbsToReturn: maximum response size read, in megabytes. Default 24.

Request format

Valsight sends one POST request with Content-Type: application/json and this body:

KeyValue
inputsThe input nodes, as an object keyed by each node’s position in the formula, written as a string: "0", "1", and so on. Each value is a cube in Table JSON.
result_levelsThe level names from resultLevels. The encoding changed in 7.3, see the example below.
messageThe message argument, or null if it was omitted.
versionThe version argument, or null if it was omitted.
formatAlways "JSON".
maximum_mbs_to_returnThe value of featureFlags.apiCall.maxMbsToReturn, as a string.

An example request body for API_CALL("https://example.com/sum", ['Node A'], ["Year", "Country"], "JSON", "1", "a message"):

{
  "inputs": {
    "0": {
      "version": "1",
      "columnMetadata": [
        {"name": "Year",    "columnType": "level", "levelId": 118},
        {"name": "Country", "columnType": "level", "levelId": 101},
        {"name": "measure", "columnType": "measure"}
      ],
      "tableMetadata": {"tableType": "FACT", "tableName": "Input 0"},
      "rowData": [["2025", "DE", "100"], ["2026", "DE", "200"]]
    }
  },
  "result_levels": "[Year, Country]",
  "message": "a message",
  "version": "1",
  "format": "JSON",
  "maximum_mbs_to_return": "24"
}
{
  "inputs": {
    "0": {
      "version": "1",
      "columnMetadata": [
        {"name": "Year",    "columnType": "level", "levelId": 118},
        {"name": "Country", "columnType": "level", "levelId": 101},
        {"name": "measure", "columnType": "measure"}
      ],
      "tableMetadata": {"tableType": "FACT", "tableName": "Input 0"},
      "rowData": [["2025", "DE", "100"], ["2026", "DE", "200"]]
    }
  },
  "result_levels": ["Year", "Country"],
  "message": "a message",
  "version": "1",
  "format": "JSON",
  "maximum_mbs_to_return": "24"
}

Because message and version are passed through untouched, they are a convenient way to switch behaviour in the service from the formula, without changing the interface.

result_levels is a single string holding a rendered list, not a JSON array. A level name may itself contain a comma, and the string gives you no way to tell that comma apart from the separator: ["Year", "Quarter, Q"] arrives as "[Year, Quarter, Q]", which is three comma-separated tokens for two levels. Where level names can contain commas, take the shape of the result from your own configuration rather than from this value.

result_levels is a JSON array. Up to 7.2 it was a single string holding a rendered list, "[Year, Country]", so a service written against an older Valsight that splits that string on commas has to be changed to read an array instead.

This is a breaking change to the request body, made because a level name may itself contain a comma: ["Year", "Quarter, Q"] used to arrive as "[Year, Quarter, Q]", three comma-separated tokens for two levels. The array form is unambiguous.

Response format

Valsight validates a known set of keys in the response and ignores any others:

  • response_status: SUCCESS or ERROR. On ERROR, Valsight displays the message in error_message. The key may be omitted entirely; only an unrecognised value is an error.
  • error_message: the text shown to the user when response_status is ERROR.
  • output: the returned node, in the Valsight Table JSON structure.

The output cube must carry exactly the levels named in resultLevels, plus a measure column. The most robust way to build its columnMetadata is to copy the entries from an input cube, because they carry the levelId values Valsight uses to map values back onto its dimensions.

An example response:

{
  "format": "JSON",
  "version": "1",
  "function_name" : "simple_plus",
  "response_status": "SUCCESS",
  "error_message": "",
  "output" : {
        "version": "1",
        "columnMetadata": [
            {
                "name": "Year",
                "columnType": "level",
                "levelId": 1
            },
            {
                "name": "measure",
                "columnType": "measure"
            }
        ],
        "rowData": [
            ["2015","50"],
            ["2016","100"],
            ["2017","150"],
            ["2018","200"]
        ]
    }
}

Errors

Every message below is shown on the node, prefixed with API_CALL -.

MessageCauseFix
You have not entered a value for the URL.The url argument is empty.Enter an endpoint.
No URLs are allowed.featureFlags.apiCall.allowedUrlsRegex is empty, which is the default.Ask an administrator to set the allow-list.
The provided URL is not allowed.The endpoint does not match the allow-list.Correct the URL, or ask an administrator to widen the allow-list.
The provided format is not supported.The format argument is not JSON.Use JSON, or omit the argument.
The total number of rows in some of the input nodes is higher than the maximum.The input nodes together exceed maxRowsToSend.Reduce the input, or ask an administrator to raise the limit.
The size of the content returned exceeds the maximum allowed limit.The response is larger than maxMbsToReturn.Return less data, or ask an administrator to raise the limit.
The external server did not respond in the given time frame.The service did not answer within timeout seconds.Make the service faster, or raise timeout.
The POST request to the external server failed.The service answered with a status outside 200–299.Check the service logs for the failing request.
The external server failed to do the calculation.The service returned response_status ERROR.Read the service’s own error_message, quoted in the notice.
The external server returned an unknown response status.response_status is present but is neither SUCCESS nor ERROR.Return one of the two values, or omit the key.
Unable to convert the output received from external server into a valid cube.output is not valid Table JSON, or its levels do not match resultLevels.Compare the cube against Response format.

Examples

Sending two nodes to a service that adds them

This example sends two nodes to a service that adds them and returns the sum per Year and Country.

Input node: 'A'

YearCountryRevenue
2025DE100
2026DE200
2027DE300
2028DE400
2029DE500

Input node: 'B'

YearCountryRevenue
2025DE350
2026DE400
2027DE450
2028DE500
2029DE550

Formula: API_CALL("https://externalServer.com/sumTwoNodes", ['Node A', 'Node B'], ["Year", "Country"])

Valsight sends nodes A and B as inputs "0" and "1", and requests the levels Year and Country back. When the service responds successfully, the result is:

YearCountryCalculationResult
2025DE100 + 350450
2026DE200 + 400600
2027DE300 + 450750
2028DE400 + 500900
2029DE500 + 5501050

Switching behaviour from the formula

This example uses message to pick a mode in the service without changing the interface.

Formula: API_CALL("https://externalServer.com/optimize", ['Volume'], ["Country"], "JSON", "1", "integer")

The service receives "message": "integer" and can branch on it, for instance to run an integer rather than a continuous optimisation. Passing message requires passing format and version first, because the optional arguments are positional.

DATA
When the external data is already uploaded as a data table, reference it directly instead of calling a live service.
Was this page helpful?