Prompt templates are used to integrate generative AI capabilities into your applications and workflows. You can create them in Prompt Builder, which is part of the Einstein 1 Studio suite of AI development tools. When you invoke prompt templates, they are first resolved, which entails surfacing all the data references in the prompt template (e.g., merge fields, related lists, flows, or Apex), and then sent through the Einstein Trust Layer, before generating a response from the large language model (LLM). Some out-of-the-box entry points allow you to invoke prompt templates from Salesforce, such as the Email Composer or Lightning Record pages with dynamic forms.
In this blog post, weโll explore how you can create custom entry points to invoke prompt templates from within your Salesforce apps using flows and Apex, and from your own apps outside Salesforce using the REST API. Be sure to also read our previous blog post on prompt templates, where we review different techniques to ground prompt templates.
Entry points for executing prompt templates
When you invoke a prompt template, it goes through several transformations to produce the final prompt, which is then sent to the LLM. The LLM response, or โcompletion,โ is also processed to produce the final generation/s that you use in your AI-enabled business workflows or apps. On top of the out-of-the-box entry points, you can initiate this process from your custom business logic implemented with Flow or Apex, and from external systems through the REST API.
The table below (also included in the previous blog post) summarizes the inputs and entry points that a prompt template may have, depending on its type.
| Prompt template type | Description | Inputs | Entry points |
| Sales Email | Draft personalized emails through Email Composer. | Contact or lead, and optionally another object of your choice | Email Composer Flow Apex REST API Copilot action |
| Field Generation | Generate text to be stored in a custom field within a record page. | An object of your choice | Record page Flow Apex REST API Copilot action |
| Flex | Generate text to be used anywhere. | Up to five objects of your choice | Flow Apex REST API Copilot action |
| Record Summary | Generate a summary for a record to be used in Einstein Copilot. | An object of your choice | Copilot action |
Letโs review each of the custom entry points in depth.
Invoking prompt templates from Flow
Every saved and activated prompt template that you create is automatically exposed as an invocable action that you can invoke from Flow using the regular Actions element. You can filter them out by selecting the Prompt Template category when creating the element.
Letโs take a look at an example. Imagine that you want to invoke a prompt template like the one below from a flow.
All templates with a specific input should have that input passed in as a related entity when invoked from a flow. We discuss the input options for each prompt template type in our previous blog post. In this example, since this is a field generation prompt template thatโs associated with the Contact object, you need to pass a contact as a related entity.
As you can see, invoking prompt templates from Flow is very straightforward, making it very convenient to incorporate AI-generated outputs into your regular business workflows.
Invoking prompt templates from Apex
To invoke prompt templates in Apex, you use classes and methods from Connect API in Apex.
This time, weโll use a slightly more complex flex prompt template as an example.
This template is used to generate social posts that allow real estate agents to promote the properties theyโre selling. Note that the prompt template body is longer than shown here. Letโs explore how to invoke it from Apex.
First, like in Flow, each prompt template will expect different inputs to be passed in, so you need to create the inputs in Apex and pass them to the template. The sample flex prompt template is associated with a Property__c custom object, so we need to pass a property record when we invoke it from Apex.
Map<String, String> property = new Map<String, String>();
property.put('id', propertyId); // Don't need to pass other field values even if referenced in the template, just the Id
ConnectApi.WrappedValue propertyValue = new ConnectApi.WrappedValue();
propertyValue.value = property;
Map<String, ConnectApi.WrappedValue> inputParams = new Map<String, ConnectApi.WrappedValue>();
inputParams.put('Input:Property', propertyValue); // Property is the API Name we gave to the input
ConnectApi.EinsteinPromptTemplateGenerationsInput executeTemplateInput = new ConnectApi.EinsteinPromptTemplateGenerationsInput();
executeTemplateInput.additionalConfig = new ConnectApi.EinsteinLlmAdditionalConfigInput();
executeTemplateInput.additionalConfig.applicationName = 'PromptBuilderPreview';
executeTemplateInput.isPreview = false;
executeTemplateInput.inputParams = inputParams;Note that in the EinsteinPromptTemplateGenerationsInput instance, we can control some parameters of the invocation. Some interesting ones are:
- The
isPreviewparameter controls whether the prompt should be just resolved and return the resolution, or resolved and then sent to the LLM to return the completion. - The
numGenerationsparameter controls how many responses you get from the LLM. The default is one, but you can return multiple completions in a single invocation if you want to choose a desired response from several options. - The
temperatureparameter controls how many risks you want the model to take. The default and minimum value is 0 (no risk), which will generate less innovative, more deterministic, but more accurate responses, and the maximum value is 1. - The
frequencyPenaltyparameter is used to control the repetitiveness of the generated tokens, taking into account how many times a token has appeared in this or in prior generations.
Finally, you perform the invocation by calling the generateMessagesForPromptTemplate method, and passing in the template API name and the EinsteinPromptTemplateGenerationsInput instance that you created.
ConnectApi.EinsteinPromptTemplateGenerationsRepresentation generationsOutput = ConnectApi.EinsteinLLM.generateMessagesForPromptTemplate(
'Generate_Social_Media_Posts',
executeTemplateInput
);The response will be an EinsteinPromptTemplateGenerationsRepresentation, containing the resolved prompt, the generations, and other parameters.
If there was a single generation, you can extract the response (of type EinsteinLLMGenerationItemOutput) text as follows.
ConnectApi.EinsteinLLMGenerationItemOutput response = generationsOutput.generations[0];
String response = response.text;
// Do something with the text, which will be valid JSON in our exampleNote that the response also includes an interesting parameter called safetyScoreRepresentation, which is a set of measures that Salesforce computes to evaluate the safety of the response by passing it through a toxicity detection model. Check the information thatโs included in the safety score.
Going back to our flex prompt template example, note that we instructed the template to return valid JSON. This is a very convenient approach when invoking prompt templates from Apex, as youโll be able to easily parse it, either in Apex or JavaScript, if the response is being sent to a Lightning web component.
As you can see, invoking prompt templates from Apex can be very useful when incorporating AI-generated outputs into more complex, back-end business logic. And of course, donโt forget that you can surface those responses in the front end, calling Apex from LWC.
Invoking prompt templates from the REST API
Finally, to invoke prompt templates from external systems, you use a resource exposed in the Connect REST API.
/einstein/prompt-templates/promptTemplateDevName/generationsSame as in Flow and Apex, you need to pass the inputs that the prompt template expects in the request body.
{
"isPreview": "false",
"inputParams": {
"valueMap": {
"Input:Property": {
"value": {
"id": "a011Q00001EQYXOQA5"
}
}
}
},
"additionalConfig": {
"numGenerations": 1,
"temperature": 0,
"frequencyPenalty": 0.0,
"presencePenalty": 0.0,
"additionalParameters": {},
"applicationName": "PromptBuilderPreview"
}
}And the response body of the generation will look something like this:
{
"generations": [
{
"parameters": "{finish_reason=stop, index=0, logprobs=null}",
"responseId": "893db990-7acb-4845-ad65-54d82606ca65",
"text": "{\n "twitter": "๐ Exciting new listing! Explore our luxurious property, [Provide:{PROPERTY NAME}], featuring [Provide:{BEDS}] beds, [Provide:{BATHS}] baths, and an asking price of [Provide:{ASKING PRICE}]. Click the link for a sneak peek! [Provide:{PICTURE}]",\n "linkedin": "๐๐ Don't miss out on this incredible opportunity! Discover the stunning property, [Provide:{PROPERTY NAME}], offering [Provide:{BEDS}] beds, [Provide:{BATHS}] baths, and an asking price of [Provide:{ASKING PRICE}]. Click the link below to see more! [Provide:{PICTURE}]",\n "blockkit": {\n "blocks": [\n {\n "type": "section",\n "text": {\n "type": "mrkdwn",\n "text": "*Luxury Property Alert!* \n\n๐๐๐\n\nIntroducing [Provide:{PROPERTY NAME}], a magnificent home with [Provide:{BEDS}] beds and [Provide:{BATHS}] baths. Priced at [Provide:{ASKING PRICE}]."\n },\n "accessory": {\n "type": "image",\n "image_url": "[Provide:{PICTURE}]",\n "alt_text": "Luxury Property"\n }\n },\n {\n "type": "divider"\n },\n {\n "type": "actions",\n "elements": [\n {\n "type": "button",\n "text": {\n "type": "plain_text",\n "text": "View Property",\n "emoji": true\n },\n "url": "https://d1q000001ewauuaq-dev-ed.develop.lightning.force.com/[Provide:{RECORD ID}]"\n }\n ]\n }\n ]\n }\n}"
}
],
"parameters": null,
"prompt": "You're the community manager for Dreamhouse, a real estate agency that sells luxury properties. \nCreate social media posts for twitter, linkedin and slack (block kit format) describing the property.\n\nInstructions:\n"""\nUse clear, concise, and straightforward language using the active voice and strictly avoiding the use of filler words and phrases and redundant language.\nMake sure the response is valid JSON.\nWhen you generate the posts, include the name of the property, [Provide:{PROPERTY NAME}], and explain the characteristics of the house, such as [Provide:{BATHS}], [Provide:{BEDS}]and[Provide:{ASKING PRICE}]. Also include a link to the picture of the property, [Provide:{PICTURE}]. \n\nThe twitter post should include emojis.\nThe linkedin post should include several emojis and bullets, and also have a special output formatting: Text render environment only supports Unicode and emoji. Use symbols from Unicodeโs Mathematical Alphanumeric Symbols block liberally to produce facsimiles of bold, italics, line separation, and other formatting. Examples for a sample sentence:\n\nitalics sans: ๐๐ฉ๐ฆ ๐๐ถ๐ช๐ค๐ฌ ๐๐ณ๐ฐ๐ธ๐ฏ ๐๐ฐ๐น ๐๐ถ๐ฎ๐ฑ๐ฆ๐ฅ ๐๐ท๐ฆ๐ณ ๐ต๐ฉ๐ฆ ๐ญ๐ข๐ป๐บ ๐ฅ๐ฐ๐จ.\nbold sans: ๐ง๐ต๐ฒ ๐ค๐๐ถ๐ฐ๐ธ ๐๐ฟ๐ผ๐๐ป ๐๐ผ๐
๐๐๐บ๐ฝ๐ฒ๐ฑ ๐ข๐๐ฒ๐ฟ ๐๐ต๐ฒ ๐น๐ฎ๐๐ ๐ฑ๐ผ๐ด.\nbold italic sans: ๐๐๐ ๐๐ช๐๐๐ ๐ฝ๐ง๐ค๐ฌ๐ฃ ๐๐ค๐ญ ๐
๐ช๐ข๐ฅ๐๐ ๐๐ซ๐๐ง ๐ฉ๐๐ ๐ก๐๐ฏ๐ฎ ๐๐ค๐.\nitalics serif: ๐โ๐ ๐๐ข๐๐๐ ๐ต๐๐๐ค๐ ๐น๐๐ฅ ๐ฝ๐ข๐๐๐๐ ๐๐ฃ๐๐ ๐กโ๐ ๐๐๐ง๐ฆ ๐๐๐.\n\nThe block kit code should be valid block kit code.\nWhen you generate the block kit code: \n- Add several sections. \n- Include the name of the property, [Provide:{PROPERTY NAME}], and explain the characteristics of the house, such as [Provide:{BATHS}], [Provide:{BEDS}] and [Provide:{ASKING PRICE}]. \n- Include a the picture of the property, which image_url is [Provide:{PICTURE}]. \n- Include a button which url points to https://d1q000001ewauuaq-dev-ed.develop.lightning.force.com/[Provide:{RECORD ID}]\n- Include emoticons so the post is more visual.\n\nExample of block kit code:\n\n{\n "blocks": [\n {\n "type": "section",\n "text": {\n "type": "mrkdwn",\n "text": "Hello, Assistant to the Regional Manager Dwight! *Michael Scott* wants to know where you'd like to take the Paper Company investors to dinner tonight.\n\n *Please select a restaurant:*"\n }\n },\n {\n "type": "divider"\n },\n {\n "type": "section",\n "text": {\n "type": "mrkdwn",\n "text": "*Farmhouse Thai Cuisine*\n:star::star::star::star: 1528 reviews\n They do have some vegan options, like the roti and curry, plus they have a ton of salad stuff and noodles can be ordered without meat!! They have something for everyone here"\n },\n "accessory": {\n "type": "image",\n "image_url": "https://s3-media3.fl.yelpcdn.com/bphoto/c7ed05m9lC2EmA3Aruue7A/o.jpg",\n "alt_text": "alt text for image"\n }\n },\n {\n "type": "section",\n "text": {\n "type": "mrkdwn",\n "text": "*Kin Khao*\n:star::star::star::star: 1638 reviews\n The sticky rice also goes wonderfully with the caramelized pork belly, which is absolutely melt-in-your-mouth and so soft."\n },\n "accessory": {\n "type": "image",\n "image_url": "https://s3-media2.fl.yelpcdn.com/bphoto/korel-1YjNtFtJlMTaC26A/o.jpg",\n "alt_text": "alt text for image"\n }\n },\n {\n "type": "section",\n "text": {\n "type": "mrkdwn",\n "text": "*Ler Ros*\n:star::star::star::star: 2082 reviews\n I would really recommend the Yum Koh Moo Yang - Spicy lime dressing and roasted quick marinated pork shoulder, basil leaves, chili & rice powder."\n },\n "accessory": {\n "type": "image",\n "image_url": "https://s3-media2.fl.yelpcdn.com/bphoto/DawwNigKJ2ckPeDeDM7jAg/o.jpg",\n "alt_text": "alt text for image"\n }\n },\n {\n "type": "divider"\n },\n {\n "type": "actions",\n "elements": [\n {\n "type": "button",\n "text": {\n "type": "plain_text",\n "text": "Farmhouse",\n "emoji": true\n },\n "value": "click_me_123"\n },\n {\n "type": "button",\n "text": {\n "type": "plain_text",\n "text": "Kin Khao",\n "emoji": true\n },\n "value": "click_me_123",\n "url": "https://google.com"\n },\n {\n "type": "button",\n "text": {\n "type": "plain_text",\n "text": "Ler Ros",\n "emoji": true\n },\n "value": "click_me_123",\n "url": "https://google.com"\n }\n ]\n }\n ]\n}\n\nThe response should have the next format:\n{\n "twitter": [here goes the twitter post, that should have less than 280 characters],\n "linkedin": [here goes the linkedin post, that should have between 1500 and 2000 characters], \n "blockkit": [here goes the block kit post], \n}\n\n"""\n\nNow generate the posts.\n\n\n",
"promptTemplateDevName": "Generate_Social_Media_Posts",
"requestId": "chatcmpl-97KqPl1TEiOgMdnKKPQ9aVs7rPJGr"
}See a sample request to this resource in the Salesforce Platform Postman collection, and watch this video to learn how to set up Postman to test Salesforceโs APIs.
Thanks to the Connect REST API, itโs not only possible to invoke prompt templates programmatically within the Salesforce Platform, but also from third-party systems. Now, let your imagination fly and think about all the fantastic use cases that you could implement by using this capability!
Try it out!
Prompt Builder requires an Einstein 1 Edition license, or it can be purchased as an add-on. You can try it out for free by requesting a five-day trial org as part of the new Quick Start: Prompt Builder module on Trailhead. As a bonus, Einstein Copilot will be included in the trail org as well. And if you want to know more, take a look at this comprehensive list of resources:
- Learn more about Prompt Builder
- Documentation: Integrate Prompt Templates with Salesforce Features
- Blog post: Ground Your Prompt Templates with Data Using Flow or Apex
- Blog post: Inside the Einstein Trust Layer
- Video: Inside the Einstein Trust Layer
- GitHub: Repo where youโll find the examples shown in this post
About the author
Alba Rivas works as a Principal Developer Advocate at Salesforce. You can follow her on Twitter or LinkedIn.



