API calls for email agents
Email agents run API call actions with the same URL, header and request body fields as voice agents. On email, templates use a smaller syntax, and they can use the incoming email, the Stellar user who sent the reply, and values returned by earlier API calls. This page covers what is specific to email.
Variables
Use {{ .variables.mail.FIELD }} to insert a field of the incoming email:
| Variable | Description |
|---|---|
mail.id | Stellar's id for the email |
mail.from_address | The sender's address. For Zendesk, the ticket requester |
mail.from_name | The sender's name, when known |
mail.subject | The subject, when there is one |
mail.ticket_id | The Zendesk ticket id. Zendesk only |
mail.external_conversation_id | The ticket id for Zendesk, or the conversation id for Outlook and Exchange |
mail.internet_message_id | The email's Message-ID. Not available for Zendesk |
mail.external_message_id | The provider's id for the message |
mail.has_attachments | true or false |
In On send actions, {{ .variables.stellar.user.id }}, {{ .variables.stellar.user.email }} and {{ .variables.stellar.user.name }} hold the Stellar user who sent the reply:
- They are set when someone clicks Send or Create draft in Studio. For Create draft, that is the person who created the draft, even if someone else later sends it from Outlook.
- They are empty for replies sent or drafted automatically, replies sent from Outlook or Zendesk directly, requests made with an API key or API token, and every On receive action.
- When a Stellar support user or a user from a parent organization sends the reply, they hold that person's details.
Output variables from earlier API calls are available as {{ .variables.NAME }}. See Chaining API calls.
The agent can also read these variables at the start of each run: the email's mail fields, and in On send actions the stellar.user fields. Instructions and action parameter descriptions can refer to them, for example "use the mail.internet_message_id variable". The agent is told not to share them with the customer unless your instructions say so. Output variables reach the agent through each API call's result, with Sensitive values redacted.
Templates
Email templates support two forms:
- Field access:
{{ .parameters.order_id }}or{{ .variables.mail.subject }}. toJsonof a field:{{ toJson .variables.mail.subject }}. Use it in request bodies: it adds the quotes and escapes characters, so text from an email cannot break your JSON.
Other template syntax, such as if, range or functions other than toJson, is rejected when you save. Static variables work as {{ .static_variables.NAME }}.
A missing value renders as empty text, or as null inside toJson. An object or a list needs toJson; without it, the call fails.
URL: .variables values are URL-encoded, and a missing one renders empty. toJson is not available in URLs. URL parameters work as on voice: a missing one fails the call, and a parameter used in the URL is not sent again in the query or the body.
Request body:
- GET requests never send a body. Parameters go in the query.
- DELETE requests send the body template when there is one, and otherwise send parameters in the query.
- POST, PUT and PATCH requests send the body template when there is one, and otherwise send parameters as a JSON object.
A body is sent with Content-Type: application/json unless you set a Content-Type header yourself.
Headers: value headers can use templates. Secret headers and headers from an API connection are sent exactly as written.
Chaining API calls
When an API call returns, its output variables are available to the next API call in the same run. For example, look up a customer, then add a note:
lookup_customercallsGET https://crm.example.com/customers?email={{ .variables.mail.from_address }}and has the output variablecustomer.idwith the JSONPath$.results[0].id.add_notecallsPOST https://crm.example.com/customers/{{ .variables.customer.id }}/noteswith the body{"subject": {{ toJson .variables.mail.subject }}}.
Tell the agent the order in the action description, such as "Call this after lookup_customer."
Each run starts empty: output variables from On receive actions are not available to On send actions.
Credentials
A common chain fetches a token in one call and sends it in the next:
get_tokenreturns{"access_token": "..."}. Give it the output variableauth.tokenwith the JSONPath$.access_token, and turn on Sensitive.- Later calls send the header
Authorization: Bearer {{ .variables.auth.token }}.
A Sensitive value is replaced with **REDACTED** in what the agent sees and in processing history, in the output variable and in any response field that holds exactly that value, including the responses and errors of later API calls in the same run. Matching is by exact value, so a value inside longer text, such as Bearer <token>, is not replaced. On email agents, turning off Expose to AI does not hide a value; use Sensitive.
Send a fetched token in a header. Never put a token in a request body: request bodies are saved as sent, and the agent sees them. Avoid tokens in the URL, because URLs can be logged. Send long-lived secrets as secret headers. Responses often carry more than one credential, such as refresh_token: give each its own Sensitive output variable. For standard OAuth2 client credentials, use an authentication connector instead of chaining.
Save errors and failed calls
Saving an email agent checks every API call template and reports the first problem with the action and the field, for example Action "add_note" URL: "mail.subjet" is not a mail variable. It rejects:
- syntax other than field access and
toJson, andtoJsonin a URL; - a
mailorstellar.userfield that does not exist; - a
.variablesname that no API call action defines as an output variable; - an output variable whose name starts with
mailorstellar.
A call fails before anything is sent when a URL parameter is missing, when a template renders an object or a list without toJson, or when a template uses syntax outside the supported subset, which can happen in a version saved before these checks existed. The agent receives the error, and processing history shows it on the action.
Next steps
- Read API call actions for every field an API call action has
- Manage static variables used in your templates
- Set up a Custom API integration to share base URLs, auth, and headers across agents