ExternalCallout policy

This pageapplies toApigee andApigee hybrid.

View Apigee Edge documentation.

The ExternalCallout policy enables you to send gRPC requests to your gRPC server to implement custom behavior that isn't supported by Apigee policies. In your server's code, you can easily access and modify flow variables within a proxy's flow.

Apigee communicates with a gRPC server through an ExternalCallout policy via an API. Apigee uses the API to sendflow variables to the gRPC server. Within your gRPC server, you can read—and depending on the variable, modify— the flow variables listed in theFlow variables reference page, as well as additional variables you specify within the policy's XML.

If you configure the gRPC server with Apigee and include this policy in a proxy, Apigee will handle API requests as follows:

  1. Apigee sends a message containing the flow variables to your gRPC server.
  2. Your gRPC server code executes, accessing and modifying variables as defined in the code. The gRPC server then sends a response containing all the flow variables back to Apigee.
  3. Apigee reads the response from your gRPC server. If any variables are added or modifiable flow variables are modified, they are updated in Apigee.

This policy is aStandard policy and can be deployed to any environment type. For information on policy types and availability with each environment type, seePolicy types.

To learn more about sending gRPC requests, see the following links:

<ExternalCallout>

Defines an ExternalCallout policy.

<ExternalCallout async="true" continueOnError="true" enabled="true" name="EC">

This element has the following attributes that are common to all policies:

AttributeDefaultRequired?Description
nameN/ARequired

The internal name of the policy. The value of thename attribute can contain letters, numbers, spaces, hyphens, underscores, and periods. This value cannot exceed 255 characters.

Optionally, use the<DisplayName> element to label the policy in the management UI proxy editor with a different, natural-language name.

continueOnErrorfalseOptionalSet tofalse to return an error when a policy fails. This is expected behavior for most policies. Set totrue to have flow execution continue even after a policy fails. See also:
enabledtrueOptionalSet totrue to enforce the policy. Set tofalse toturn off the policy. The policy will not be enforced even if it remains attached to a flow.
async  falseDeprecatedThis attribute is deprecated.

The following table describes the child elements of<ExternalCallout>.

Child ElementRequiredDescription
<TimeoutMs>RequiredThe request timeout in milliseconds for gRPC requests.
<GrpcConnection>RequiredSpecifies the name of an existingTargetServer to be the gRPC server to send requests to.
<Configurations>OptionalAllows you to configure various aspects of the ExternalCallout policy, including the<Property> and<FlowVariable> elements.

Example 1

Working examples of ExternalCallout are available atExternal Callout Samples on GitHub.

The following example illustrates an ExternalCallout policy configuration.

<ExternalCalloutenabled="true"continueOnError="false"name="ExternalCallout-1"><DisplayName>ExternalCallout1</DisplayName><TimeoutMs>5000</TimeoutMs><GrpcConnection><Servername="external-target-server"/></GrpcConnection><Configurations><Propertyname="with.request.content">true</Property><Propertyname="with.request.headers">false</Property><Propertyname="with.response.content">true</Property><Propertyname="with.response.headers">false</Property><FlowVariable>example1.flow.variable</FlowVariable><FlowVariable>example2.flow.variable</FlowVariable></Configurations><ExternalCallout>

The example sends a request to an external gRPC server represented by the TargetServer namedexternal-target-server, with the following configurations:

  • <Property>: Include request and response content, but not the request and response headers, in the request sent to the gRPC server.
  • <FlowVariable>: Include additionalflow variablesexample1.flow.variable andexample2.flow.variable, specified by theFlowVariable elements, in the request sent to the gRPC server.

Example 2

In the following example, theuseTargetUrl attribute of theAudience element is set totrue. WhenuseTargetUrl istrue, the hostname of the gRPC target server is used as the audience. Forexample, if the host of the server ismy-grpc-server-java.a.run.app, then the audienceused will behttps://my-grpc-server-java.a.run.app.

Apigee hybrid users: If you use Apigee hybrid, note that theuseTargetUrl attribute is available in Apigee hybrid version 1.8 and later versions.
<ExternalCalloutcontinueOnError="false"enabled="true"name="External-Callout-1"><DisplayName>External-Callout-1</DisplayName><GrpcConnection><Servername="cloud_run_server_name"/><Authentication><GoogleIDToken><AudienceuseTargetUrl="true"/></GoogleIDToken></Authentication></GrpcConnection><TimeoutMs>5000</TimeoutMs><Configurations><Propertyname="with.request.content">true</Property><Propertyname="with.request.headers">true</Property><Propertyname="with.response.content">true</Property><Propertyname="with.response.headers">true</Property><FlowVariable>example.flow.variable</FlowVariable><FlowVariable>another.flow.variable</FlowVariable></Configurations></ExternalCallout>

Child element reference

The following sections describe the child elements ofExternalCallout.

<TimeoutMs>

The request timeout in milliseconds for gRPC requests.<TimeoutMs> must be a positive number.

<GrpcConnection>

The<GrpcConnection> element sets the gRPC server to be an existingTargetServer, specified by thename attribute. See theTargetServer resource reference page.

Note: The protocol for theTargetServer must beGRPC.

For example, the following code

<GrpcConnection>  <Server name="external-target-server"/></GrpcConnection>

specifies the gRPC server to be an existingTargetServer namedexternal-target-server.

Use the<Authentication> element (described later in this section) to generate a Google-issuedOpenID Connect token to make authenticated calls to gRPC-based services, such as custom services hosted inCloud Run.

The following table describes the child elements of<GrpcConnection>.

Child ElementRequired?Description
<Server> elementRequiredSpecifies the gRPC server.
<Authentication> elementOptionalGenerates a Google-issuedOpenID Connect token to make authenticated calls to gRPC-based services, such asCloud Run.

<Server> element

Specifies the gRPC server.

The following table describes the attributes of the<Server> element.

AttributeDescriptionDefaultPresenceType
name

The name of an existingTargetServer to be the gRPC server to send requests to.

N/ARequiredString

<Authentication> element

Apigee hybrid users: If you are using Apigee hybrid, note that this feature is only supported for Apigee hybrid v1.6.x and later versions.

Generates a Google-issuedOpenID Connect token to make authenticated calls to gRPC-based services, such as custom services hosted inCloud Run. Use of this element requires setup and deployment steps described inUsing Google authentication. Withproper setup, the policy creates an authentication token for you and adds it to the service request.

This element has one required child element:GoogleIDToken.

DefaultN/A
Required?Optional.
TypeComplex type
Parent Element<GrpcConnection>
Child Elements<GoogleIDToken>

TheAuthentication element uses the following syntax:

Syntax

<ExternalCallout>...<GrpcConnection><Servername="cloud_run_server_name"/><Authentication><HeaderNameref="FLOW_VARIABLE">STRING</HeaderName><GoogleIDToken><Audienceref="variable-1">STRING</Audience><IncludeEmailref="variable-2">BOOLEAN</IncludeEmail></GoogleIDToken></Authentication></GrpcConnection></ExternalCallout>

Example

The following example shows theGoogleIDToken element:

<ExternalCalloutcontinueOnError="false"enabled="true"name="External-Callout-1"><DisplayName>External-Callout-1</DisplayName><GrpcConnection><Servername="cloud_run_server_name"/><Authentication><HeaderNameref='my-variable'>X-Serverless-Authorization</HeaderName><GoogleIDToken><Audience>https://cloudrun-hostname.a.run.app</Audience></GoogleIDToken></Authentication></GrpcConnection><TimeoutMs>5000</TimeoutMs><Configurations><Propertyname="with.request.content">true</Property><Propertyname="with.request.headers">true</Property><Propertyname="with.response.content">true</Property><Propertyname="with.response.headers">true</Property><FlowVariable>example.flow.variable</FlowVariable><FlowVariable>another.flow.variable</FlowVariable></Configurations></ExternalCallout>
Attributes

None.

<HeaderName> child element

By default, when an Authentication configuration is present, Apigee generates a bearer token and injects it into theAuthorization header in the message sent to the target system. TheHeaderName element allows you to specify the name of a different header to hold that bearer token. This feature is particularly useful when the target is a Cloud Run service that uses theX-Serverless-Authorization header. TheAuthorization header, if present, is left unmodified and also sent in the request.

DefaultN/A
Required?No
TypeString
Parent Element<Authentication>
Child ElementsNone

TheHeaderName element uses the following syntax:

Syntax

<ExternalCallout>...  <Authentication>    <HeaderName ref="FLOW_VARIABLE">STRING</HeaderName>    <GoogleIDToken>    ...    </GoogleIDToken>  </Authentication>  ...</ExternalCallout>

With static string

In this example, the generated bearer token is added, by default, to a header namedX-Serverless-Authorization that is sent to the target system. TheAuthorization header, if present, is left unmodified and also sent in the request.

<Authentication>  <HeaderName>X-Serverless-Authorization</HeaderName>  <GoogleIDToken>    <Audience>https://cloudrun-hostname.a.run.app</Audience>  </GoogleIDToken></Authentication>

With variable reference

In this example, the generated bearer token is added, by default, to a header namedX-Serverless-Authorization that is sent to the target system. Ifmy-variable has a value, that value is used instead of the default string. TheAuthorization header, if present, is left unmodified and also sent in the request.

<Authentication><HeaderNameref='my-variable'>X-Serverless-Authorization</HeaderName><GoogleIDToken><Audience>https://cloudrun-hostname.a.run.app</Audience></GoogleIDToken></Authentication>
<GoogleIDToken> child element

Generates Google-issued OpenID Connect tokens to make authenticated calls to Google services, such as custom services hosted inCloud Run.

DefaultN/A
Required?Required
TypeString
Parent Element<Authentication>
Child Elements<Audience>
<IncludeEmail>

TheGoogleIDToken element uses the following syntax:

Syntax

<ExternalCallout>...<GrpcConnection><Servername="cloud_run_server_name"/><Authentication><GoogleIDToken><Audienceref="context-variable"useTargetUrl='BOOLEAN'>STRING</Audience><IncludeEmailref="context-variable">BOOLEAN</IncludeEmail></GoogleIDToken></Authentication></GrpcConnection></ExternalCallout>

Example

The following example shows theGoogleIDToken element:

<Authentication>  <GoogleIDToken>      <Audience>https://httpserver0-bar.run.app</Audience>      <IncludeEmail>true</IncludeEmail>  </GoogleIDToken></Authentication>
<Audience> child element

The audience for the generated authentication token, such as the API or account that the token grants access to.

If the value ofAudience is empty, theref is empty or resolves to an empty value, anduseTargetUrl istrue, then "https://" + (hostname of the gRPC target server) is used as the audience. For example, if the host of the server ismy-grpc-server-java.a.run.app, then the audience used will behttps://my-grpc-server-java.a.run.app.

By default,useTargetUrl isfalse.

Apigee hybrid users: If you use Apigee hybrid, note that theuseTargetUrl attribute is available in Apigee hybrid version 1.8 and later versions.
<Audience>explicit-audience-value-here</Audience>or:<Audienceref='variable-name-here'/>or:<Audienceref='variable-name-here'useTargetUrl='true'/>or:<AudienceuseTargetUrl='true'/>
DefaultN/A
Required?Required
TypeString
Parent Element<GoogleIDToken>
Child ElementsNone.
<IncludeEmail> child element

If set totrue, the generated authentication token will contain the service accountemail andemail_verified claims.

Defaultfalse
Required?Optional
TypeBoolean
Parent Element<GoogleIDToken>
Child ElementsNone.

<Configurations>

The<Configurations> element allows you to configure various aspects of the ExternalCallout policy, including<Property> and<FlowVariable>.

The following table describes the child elements of<Configurations>.

Child ElementRequired?Description
<Property>Required

Specifies whether request/response headers and/or content will be sent to the server. Possible values aretrue orfalse. The default isfalse.

<FlowVariable>Required

Specifies what additional flow variables should be sent to the server.

<Property>

The<Property> element specifies whether request/response headers and/or content will be sent to the server. Possible values aretrue (the item will be sent) orfalse (the item won't be sent). The default value isfalse.

The following table describes the attributes of the<Property> element.

AttributeDescriptionDefaultPresenceType
name

Specifies what content will be sent to the server. Possible values forname are:

  • with.request.content
  • with.request.headers
  • with.response.content
  • with.response.headers
N/ARequiredString

<FlowVariable>

The<FlowVariable> element specifies what additional flow variables will be sent to the server. The value of<FlowVariable> is a prefix of a variable, rather than the full variable name. For example , if the element isa.b.c, the value of a variable nameda.b.c will be sent to the server. Similarly, the value of a variable nameda.b.c.my-variable will be sent to the server. But the value of a variable nameda.x.another-variable will not be sent, because it does not have the prefixa.b.c. Here are some examples

<Configurations>  <FlowVariable>a.b.c</FlowVariable>  <FlowVariable>d.e.f</FlowVariable></Configurations>

Error Reference

Deployment errors

Error nameCause
FAILED_PRECONDITIONThis error happens if the service account is missing when the proxy is configured with the<Authentication> tag.

For example:

Deployment of \"organizations/foo/apis/apiproxy/revisions/1\"requires a service account identity, but one was not providedwith the request.
PERMISSION_DENIEDThis error happens if there is a permission problem with the service account if the proxy is configured with the <Authentication> tag. Possible causes:
  • The service account does not exist.
  • The service account was not created in the same Google Cloud project as the Apigee organization.
  • The deployer does haveiam.serviceAccounts.actAs permission on the service account. For details, seeAbout service account permissions.

Runtime errors

The table below describes runtime errors, which can occur when the policy executes.

Fault codeHTTP StatusCause
GrpcTlsInitFailed500

This error will occur if there are any issues with initializing TLS with the gRPC server (such as Keystore or truststore issues).

steps.externalcallout.[error_code]500

[error_code] is determined by the Fault message'serrorCode field. The fault string of the error will be the fault message'sfaultstring field.

steps.externalcallout.ExecutionError500

This error will occur if any other exception occurs during the execution of this policy. The underlying exception will be exposed in the faultstring. If there was an issue with the credentials to the gRPC server, the error will look something like this:

{  "fault": {    "faultstring": "Encountered the following exception while sending the gRPC request or     processing the response: [io.grpc.StatusRuntimeException: UNAVAILABLE: Credentials failed     to obtain metadata].",    "detail": {      "errorcode": "steps.externalcallout.ExecutionError"    }  }}

You can look at the logs of the MP for further debugging pointers.

googletoken.EmptyIDTokenAudience500

<GoogleIDToken> is enabled butuseTargetUrl is set to false and no value is provided to<Audience> either directly or through reference at the time of error.

steps.externalcallout.ExecutionError

with fault string:

Encountered the following exception while sending the gRPC request or processing the response: [io.grpc.StatusRuntimeException: UNAVAILABLE: Credentials failed to obtain metadata]

500

This error happens if the API proxy is configured with the<Authentication> element. Possible causes:

  • The service account deployed with the proxy:
    • does not exist in your project (it existed when deployed, but was deleted after deployment)
    • has been disabled
    • (Apigee hybrid only) has not granted theroles/iam.serviceAccountTokenCreator role on theapigee-runtime service account.
  • (Apigee hybrid only) TheIAMCredentials API is disabled in the source project of theapigee-runtime service account.

    Note: For Apigee hybrid only, check the runtime container's log and search forexternalcallout.ExecutionError to find more detailed error messages that may help with debugging the problem.

steps.externalcallout.ExecutionError with faultstring containingPERMISSION DENIED.

For example, the faultstring will look like the following for Cloud Run:

Encountered the following exception while sending the gRPCrequest or processing the response: [io.grpc.StatusRuntimeException:PERMISSION_DENIED: HTTP status code 403 …]

500

This error happens if the API proxy is configured with the<Authentication> element. Possible causes:

  • The proxy service account exists and is enabled but does not have the right permissions to access the service.
  • The service requires authentication but the request did not have an authentication header (For example: the authentication XML was not included in the policy XML).

Miscellaneous errors

The table below describes miscellaneous errors. See the cause for more details.

Fault codeCause
ReferencesExistToGrpcServer

This error will occur if a user tries to delete a gRPC target server, but the server is still being used by other policies.

Faults

The fault variables in the following table are set for all policies by default. See Variables specific to policy errors.

VariablesWhereExamples
fault.name="fault_name"fault_name is the name of the fault, as listed in the Runtime errors table above. The fault name is the last part of the fault code.fault.name matches "ExecutionError".
externalcallout.[policy_name].failedpolicy_name is the user-specified name of the policy that threw the fault.externalcallout.ExternalCallout-1.failed = true

Related topics

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2025-12-17 UTC.