ExternalCallout policy Stay organized with collections Save and categorize content based on your preferences.
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:
- Apigee sends a message containing the flow variables to your gRPC server.
- 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.
- 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:
| Attribute | Default | Required? | Description |
|---|---|---|---|
name | N/A | Required | The internal name of the policy. The value of the Optionally, use the |
continueOnError | false | Optional | Set 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: |
enabled | true | Optional | Set 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 | false | Deprecated | This attribute is deprecated. |
The following table describes the child elements of<ExternalCallout>.
| Child Element | Required | Description |
|---|---|---|
<TimeoutMs> | Required | The request timeout in milliseconds for gRPC requests. |
<GrpcConnection> | Required | Specifies the name of an existingTargetServer to be the gRPC server to send requests to. |
<Configurations> | Optional | Allows 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.variableandexample2.flow.variable, specified by theFlowVariableelements, 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.
useTargetUrl 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 Element | Required? | Description |
|---|---|---|
<Server> element | Required | Specifies the gRPC server. |
<Authentication> element | Optional | Generates 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.
| Attribute | Description | Default | Presence | Type |
|---|---|---|---|---|
name | The name of an existing | N/A | Required | String |
<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.
| Default | N/A |
| Required? | Optional. |
| Type | Complex 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.
| Default | N/A |
| Required? | No |
| Type | String |
| Parent Element | <Authentication> |
| Child Elements | None |
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.
| Default | N/A |
| Required? | Required |
| Type | String |
| 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.
useTargetUrl 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'/>
| Default | N/A |
| Required? | Required |
| Type | String |
| Parent Element | <GoogleIDToken> |
| Child Elements | None. |
<IncludeEmail> child element
If set totrue, the generated authentication token will contain the service accountemail andemail_verified claims.
| Default | false |
| Required? | Optional |
| Type | Boolean |
| Parent Element | <GoogleIDToken> |
| Child Elements | None. |
<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 Element | Required? | Description |
|---|---|---|
<Property> | Required | Specifies whether request/response headers and/or content will be sent to the server. Possible values are |
<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.
| Attribute | Description | Default | Presence | Type |
|---|---|---|---|---|
name | Specifies what content will be sent to the server. Possible values for
| N/A | Required | String |
<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 thea.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 name | Cause |
|---|---|
FAILED_PRECONDITION | This 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_DENIED | This error happens if there is a permission problem with the service account if the proxy is configured with the <Authentication> tag. Possible causes:
|
Runtime errors
The table below describes runtime errors, which can occur when the policy executes.
| Fault code | HTTP Status | Cause |
|---|---|---|
GrpcTlsInitFailed | 500 | 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 |
|
steps.externalcallout.ExecutionError | 500 | 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.EmptyIDTokenAudience | 500 |
|
steps.externalcallout.ExecutionErrorwith fault string:
| 500 | This error happens if the API proxy is configured with the
|
steps.externalcallout.ExecutionError with faultstring containingPERMISSION DENIED.For example, the faultstring will look like the following for Cloud Run:
| 500 | This error happens if the API proxy is configured with the
|
Miscellaneous errors
The table below describes miscellaneous errors. See the cause for more details.
| Fault code | Cause |
|---|---|
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.
| Variables | Where | Examples |
|---|---|---|
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].failed | policy_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.