SDK Reference: Confidential HTTP Client
The Confidential HTTP Client lets you make privacy-preserving requests to external APIs from your workflow. Unlike the regular http.Client, the request executes inside a secure enclave, secrets are injected via templates, and responses can be optionally encrypted.
- For use cases and a conceptual overview, see The Confidential HTTP Capability
- Guide: Making Confidential Requests
Quick reference
| Method | Description |
|---|---|
client.SendRequest | Makes a confidential HTTP request. |
Core types
confidentialhttp.ConfidentialHTTPRequest
The top-level request type that combines an HTTP request with Vault DON secrets and encryption settings.
Field | Type | Description |
|---|---|---|
Request | *HTTPRequest | The HTTP request to execute inside the enclave. See HTTPRequest. |
VaultDonSecrets | []*SecretIdentifier | Vault DON secrets for enclave-only {{.key}} substitution in the request (SecretIdentifier). Use this when credentials or other sensitive template values must stay out of Workflow DON execution—not replaceable by pasting runtime.GetSecret() output into headers or body. See what stays confidential and Making Confidential Requests. |
confidentialhttp.HTTPRequest
Defines the HTTP request that will be executed inside the enclave.
Field | Type | Description |
|---|---|---|
Url | string | The URL of the API endpoint. |
Method | string | The HTTP method (e.g., "GET", "POST"). |
Body | isHTTPRequest_Body | The request body. Use HTTPRequest_BodyString for string templates or HTTPRequest_BodyBytes for raw bytes. |
MultiHeaders | map[string]*HeaderValues | Request headers. Supports multiple values per key and template syntax for secret injection. |
TemplatePublicValues | map[string]string | Public (non-secret) values used to fill template placeholders in the body and headers. |
CustomRootCaCertPem | []byte | Optional custom root CA certificate (PEM format) for verifying the external server's TLS certificate. |
Timeout | *durationpb.Duration | Optional request timeout. |
EncryptOutput | bool | If true, encrypts the response body before it leaves the enclave. See Response encryption. Default: false. |
Setting the request body
The Body field is a oneof type with two options:
String template (recommended for secret injection):
Body: &confidentialhttp.HTTPRequest_BodyString{
BodyString: `{"auth": "{{.myApiKey}}", "action": "getData"}`,
},
Raw bytes:
Body: &confidentialhttp.HTTPRequest_BodyBytes{
BodyBytes: []byte(`{"action": "getData"}`),
},
confidentialhttp.HTTPResponse
The response returned from the enclave after the HTTP request completes.
| Field | Type | Description |
|---|---|---|
StatusCode | uint32 | The HTTP status code. |
Body | []byte | The response body. If EncryptOutput is true, this contains the encrypted body (see Response encryption). |
MultiHeaders | map[string]*HeaderValues | The HTTP response headers. |
confidentialhttp.SecretIdentifier
Identifies a secret stored in the Vault DON.
| Field | Type | Description |
|---|---|---|
Key | string | The logical name of the secret. Must match the template placeholder (e.g., "myApiKey" matches {{.myApiKey}}). |
Namespace | string | The secret namespace. |
Owner | *string | Optional. The owner address for the secret. |
confidentialhttp.HeaderValues
Represents multiple values for a single HTTP header key.
| Field | Type | Description |
|---|---|---|
Values | []string | The header values. Supports template syntax for secret injection (e.g., "Basic {{.myToken}}"). |
Making requests
client.SendRequest
Makes a confidential HTTP request. The request executes inside a secure enclave, so unlike the regular HTTP client, there is no need to wrap this call in cre.RunInNodeMode.
Signature:
func (c *Client) SendRequest(runtime cre.Runtime, input *ConfidentialHTTPRequest) cre.Promise[*HTTPResponse]
Parameters:
runtime: Thecre.Runtimefrom your trigger callback.input: A*ConfidentialHTTPRequestcontaining the request and secrets.
Returns:
cre.Promise[*HTTPResponse]
Example:
client := &confidentialhttp.Client{}
resp, err := client.SendRequest(runtime, &confidentialhttp.ConfidentialHTTPRequest{
Request: &confidentialhttp.HTTPRequest{
Url: config.URL,
Method: "POST",
Body: &confidentialhttp.HTTPRequest_BodyString{BodyString: `{"auth": "{{.apiKey}}"}`},
MultiHeaders: map[string]*confidentialhttp.HeaderValues{
"Content-Type": {Values: []string{"application/json"}},
"Authorization": {Values: []string{"Basic {{.apiKey}}"}},
},
EncryptOutput: false,
},
VaultDonSecrets: []*confidentialhttp.SecretIdentifier{
{Key: "apiKey"},
},
}).Await()
if err != nil {
return Result{}, err
}
// Parse resp.Body...
Guide: Making Confidential Requests
Template syntax
Secrets are injected into the request body and headers using Go template syntax: {{.secretName}}. The placeholder name must match the Key field in the corresponding SecretIdentifier.
Body template:
Body: &confidentialhttp.HTTPRequest_BodyString{
BodyString: `{"apiKey": "{{.myApiKey}}", "method": "{{.method}}", "params": []}`,
},
Header template:
MultiHeaders: map[string]*confidentialhttp.HeaderValues{
"Authorization": {Values: []string{"Basic {{.myCredential}}"}},
},
TemplatePublicValues (optional)
Every {{.placeholder}} in your body or headers is resolved inside the enclave. By default, placeholders are filled with secrets from VaultDonSecrets. But sometimes you have a placeholder value that isn't secret — for example, an RPC method name or a public parameter. That's what TemplatePublicValues is for: it lets you inject non-secret values into the same template.
This is purely a convenience. You could always hardcode the value directly in the body string instead:
// These two are equivalent:
// Option 1: hardcoded in the body string
Body: &confidentialhttp.HTTPRequest_BodyString{BodyString: `{"method": "eth_blockNumber", "auth": "{{.apiKey}}"}`}
// Option 2: using TemplatePublicValues
Body: &confidentialhttp.HTTPRequest_BodyString{BodyString: `{"method": "{{.method}}", "auth": "{{.apiKey}}"}`}
TemplatePublicValues: map[string]string{"method": "eth_blockNumber"}
TemplatePublicValues is useful when you want to keep the template generic and pass in dynamic values (e.g., from config) without string concatenation.
Example with both secret and public values:
Request: &confidentialhttp.HTTPRequest{
Url: config.URL,
Method: "POST",
Body: &confidentialhttp.HTTPRequest_BodyString{BodyString: `{"method": "{{.rpcMethod}}", "auth": "{{.apiKey}}"}`},
TemplatePublicValues: map[string]string{
"rpcMethod": config.RPCMethod, // dynamic value from config, not a secret
},
},
VaultDonSecrets: []*confidentialhttp.SecretIdentifier{
{Key: "apiKey"}, // secret, from Vault DON
},
In this example, {{.rpcMethod}} is resolved from TemplatePublicValues (a dynamic, non-secret value from your workflow config) and {{.apiKey}} is resolved from the Vault DON (a secret). Both are resolved inside the enclave.
Response encryption
The EncryptOutput field controls whether the response body is encrypted before leaving the enclave.
EncryptOutput | Secret key provided | Behavior |
|---|---|---|
false (default) | — | Response returned unencrypted. |
true | san_marino_aes_gcm_encryption_key in VaultDonSecrets | Response AES-GCM encrypted with your symmetric key. |
true | No key provided | Response TDH2 encrypted with the Vault DON master public key. |
AES-GCM encryption is the recommended approach. Store a 256-bit (32-byte) AES key as a Vault DON secret with the identifier san_marino_aes_gcm_encryption_key, then decrypt the response in your own secure backend.
The encrypted response body is structured as nonce || ciphertext || tag.
For a complete decryption example, see the Making Confidential Requests guide.