Contents | Commands | Methods |
This guide introduces the basic statements and building blocks used in Streamscript. If you have experience with Salesforce Formulas, you'll find this straightforward.
Comments begin with a hash # sign.
# Streamscript
Variables begin with a dollar $ sign and are case sensitive. Use an equals = sign to set values.
$account = 'GenePoint'Try
Data types are text, number, boolean, list, and map, like JSON.
$text = 'Hi!' $number = 12345 $boolean = false $list = ['GenePoint', 'GenWatt'] $map = {LastName: 'Smith', AccountId: '001000000000000AAA'}Try
Templates are text in ` backticks. You can embed $variables and ${expressions} in templates.
$author = 'Mark Twain' $quote = 'Reports of my death are greatly exaggerated' Log `$author - "$quote"` # Mark Twain - "Reports of my death are greatly exaggerated"Try
Operators are used to compare variables and make formulas.
$profit = $sales - $costs $success = $profit > 10000 $vacation = $success and $weather == 'sunny'Try
Methods operate on any variable using the call .() operator. Parentheses are optional.
$greeting = 'Hello World' $length = $greeting.length # 11 $shortGreeting = $greeting.left(5) # Hello $loudGreeting = 'Hello World'.upper # HELLO WORLDTry
Commands are actions. Each command runs by itself, unlike methods which act on a variable.
They can be accompanied by one or more parameters separated by spaces - not commas.
Log 'I had no idea Abraham Lincoln loved cats.' # Logs appear in the sidebarTry
Decisions use the switch and if keywords. For alternative branches use elseif and else.
if ($weather == 'sunny') { # run if weather is sunny } switch ($weather) { hot { ... } # run when weather is hot cold { ... } # run when weather is cold default { ... } # run when weather is anything else } # if-else in one line (ternary operator) $ticket = $age > 18 ? 'Adult' : 'Child' $dealtype = $staff < 100 ? 'SMB' : 'Enterprise'Try
Loops repeat the logic between the { curly } braces. Streamscript supports while, foreach, for and do-while loops. Use continue to skip an iteration, or break to terminate the loop.
$condition = false while ($condition) { # runs while condition is true } $items = [1, 2, 3, 4, 5] foreach ($item in $items) { # loops over all the items in the list }Try
Merge Fields also known as formula tags are used to import flow resources including flow constants, flow globals, flow variables, records, and collections.
$var = {!var} $const = {!constant} $formula = {!formula} $Opportunity = {!$Record}Try
Ready for powerful commands like HTTP callouts? Try the advanced examples below!
# Send a GET or POST request $Http = Http-Get $url $headers $Http = Http-Post $url $headers $body $Http = Http-Patch $url $headers $body $Http = Http-Put $url $headers $body $Http = Http-Delete $url $headers $body # optional timeout parameter allows max request time in milliseconds $Http = Http-Get $url -timeout 3000 # optional base64 flag treats the request and response body as encoded binary data $Http = Http-Post $url $headers $body -base64 # Response map $Http.body # Represents the text of the body returned in the response $Http.status # Represents the integer status code returned in the response $Http.headers # Represents the map of HTTP headers returned in the responseTry
We recommend using the secure fields of Named Credentials as a best practice:
# Streamscript to call the Kentaa Payments API $url = 'callout:https_api_kentaa_nl/v1/actions' $headers.Api-Key = {!$Credential.Password} $Http = Post $url $headers $payload
Always set Managed Package Access to Streams unless using Legacy Named Credentials.
# Return the text value representing a datetime, eg '2022-12-24T23:59:59.999Z' $dt = Datetime-Value $year $month $day $hour $minute $second $millis -gmt # Return the text value representing a date, eg '2022-12-24' $date = Date-Value $year $month $day # Return the text value representing a time, eg '23:59:59.999Z' $time = Time-Value $hour $minute $second $millis # Return the time zone offset (in milliseconds) between the datetime and GMT $millis = Timezone-Offset $timezoneId $datetime
# Add a time interval to the start datetime, adjusting for business hours $dt = BusinessHours-Add $businessHoursId $startDatetime $intervalMillis -gmt # Return the number of milliseconds between two datetimes, adjusting for business hours $int = BusinessHours-Diff $businessHoursId $startDatetime $endDatetime # Return true if the target datetime occurs within business hours, accounting for holidays $bool = BusinessHours-IsWithin $businessHoursId $targetDatetime # For the target datetime, return next datetime when business hours are open, accounting for holidays $dt = BusinessHours-NextStartDate $businessHoursId $targetDatetime
# Convert the variable to JSON text and vice versa $text = Json-Encode $var $var = Json-Decode $text # Convert the variable to CSV text and vice versa $text = Csv-Encode $listOfRows $rows = Csv-Decode $text # Convert unsafe characters to URL-safe percent encoded format and vice versa $code = Url-Encode $text $text = Url-Decode $code # Convert the Base64 encoded binary value to text and vice versa $text = Base64-Decode $b64 $b64 = Base64-Encode $text
# Prepare a record using a map or parameters $Account = New-Account {Name: 'ACME'} $Contact = New-Contact -LastName 'Smith' $CustomObject__c = New-CustomObject__c -Id $record_id_here $nsprefix__PackagedObject__c = New-nsprefix__PackagedObject__c Try
# Query a record or records $Account = Query-Record `SELECT Name FROM Account WHERE Id = '$id'` $Contacts = Query-Records `SELECT Name FROM Contact WHERE AccountId = '$id'` $numberOfLeads = Query-Count 'SELECT COUNT() FROM Lead'Try
# DML operations $Result = Record-Insert $records -partial -system $Result = Record-Update $records -partial -system $Result = Record-Upsert $records $field -partial -system # Result map (when -partial used) $Result.id # Represents the record ID $Result.success # Did the DML operation commit $Result.errors # Text describing why the DML failed $Result.created # Upsert only: true = insert, false = update
Record-Upsert expects the name of a valid External ID field as the second parameter.
# Current user information $id = User-Info -id # Return the user's ID $name = User-Info -name # Return the user's full name $email = User-Info -email # Return the user's email address $locale = User-Info -locale # Return the user's locale, eg 'en_CA' $userName = User-Info -userName # Return the user's login name $language = User-Info -language # Return the user's language, eg 'en_US' or 'de' $userType = User-Info -userType # Return the user's type, eg 'Standard' $timeZone = User-Info -timeZone # Return the user's time zone, eg 'Asia/Tokyo' $profileId = User-Info -profileId # Return the user's profile ID $userRoleId = User-Info -userRoleId # Return the user's role IDTry
# Organization information $id = Org-Info -id # Return the organization ID $name = Org-Info -name # Return the organization name $url = Org-Info -url # Return the unique org URL, eg 'https://org.my.salesforce.com'Try
# URL information $text = Url-Info $url -host # Return the host part of the URL $text = Url-Info $url -path # Return the path part of the URL $text = Url-Info $url -port # Return the port part of the URL $text = Url-Info $url -protocol # Return the protocol part of the URL $map = Url-Info $url -query # Return the URL's query parameters as a mapTry
# Commands that transform the list: $list = List-Apply $list ${...} # Apply the logic in ${...} to each item in the list $list = List-Sort $list ${...} # Sort the list using the sort logic in ${...} $list = List-Reverse $list # Reverse the order of the list items
# Commands that return a new list: $new = List-Copy $list # Return a deep copy of the list $new = List-Filter $list ${...} # Return items that meet the condition in ${...} $new = List-Unique $list # Return the list after removing duplicate items $new = List-First $list $N # Return the first (or first N) items of the list $new = List-Last $list $N # Return the last (or last N) items of the list $new = List-Union $list $list2 # Return $list and $list2 combined into a single list $new = List-Project $list ${...} # Return a new list transformed by the logic in ${...} $map = List-ToMap $list ${...} # Return a map, keyed on the logic in ${...}
# Commands that aggregate a result: $num = List-Sum $list ${...} # Sum across each number retrieved by logic in ${...} $num = List-Avg $list ${...} # Average across each number retrieved by logic in ${...} $num = List-Min $list ${...} # Return the lowest number retrieved by logic in ${...} $num = List-Max $list ${...} # Return the highest number retrieved by logic in ${...} $txt = List-Concat $list $delim # Concatenate the list items into a single text value
$b64 = Crypto-Encode $algo $key $cleartext $iv # Encrypt cleartext with optional IV $b64 = Crypto-Decode $algo $key $ciphertext $iv # Decrypt ciphertext with optional IV $b64 = Crypto-Generate-Key $size # Generates AES key of size $b64 = Crypto-Generate-Digest $algo $data # Compute one-way hash digest $b64 = Crypto-Generate-Mac $algo $data $key # Compute message auth code (MAC) $b64 = Crypto-Sign $algo $input $keyOrCert # Compute digital signature $bool= Crypto-Verify $algo $data $sig $keyOrCert # Verify a digital signature $bool= Crypto-Verify-Hmac $algo $input $key $mac # Verify with secure compare
$bool = Script-IsTest # Return true when running under test mode $int = Script-Epoch # Return current time as milliseconds since 1970-01-01 GMT $num = Script-Random # Return a positive number greater than 0.0 and less than 1.0 $dt = Script-Now # Return current datetime, eg '2022-12-24T23:59:59.999Z' $date = Script-Today # Return today's date referencing the current user time zone $vars = Script-Flow $flow $vars # Run a flow interview with the given input variables Script-Abort $id # Aborts the queueable job, batch job, or scheduled job Script-Log $message # Write the specified message to the script log Script-Future $state ${...} # Execute logic in a @Future $any = Script-Call $class $method $args # Run an Apex class that implements Callable $id = Script-Batch $size $data $state ${...} # Execute batch logic and return ID $id = Script-Enqueue $state $delayInMins ${...} # Enqueue logic and return job ID $id = Script-Schedule $name $cron $state ${...} # Schedule logic and return ID $var = Script-RunAs $state $nc ${...} # Run logic as another user and return any value
Script-Flow accepts a $variables
map that includes keys for both inputs and outputs. This is due to Flow variables being able to serve both purposes. When the output keys are present, the map will be populated with any output values generated by the flow.
$bool = $text.isBlank() # Return true if the text is empty '' or null $int = $text.length() # Return how many Unicode characters the text contains $bool = $text.startsWith($prefix) # Return true if the text begins with the specified prefix $bool = $text.contains($fragment) # Return true if the text contains the fragment $bool = $text.endsWith($suffix) # Return true if the text ends with the specified suffix $list = $text.chars() # Return the list of character codes representing the text $int = $text.charAt($index) # Return the value of the character at the specified index $int = $text.find($fragment) # Return the index of the first occurrence, or -1 otherwise $text = $text.left($length) # Return the leftmost characters for the specified length $text = $text.mid($start, $len) # Return the text from the start index to the length given $text = $text.right($length) # Return the rightmost characters for the specified length $text = $text.replace($find, $re) # Replace each $find occurrence in $text with $replace $list = $text.split($regexp) # Return a list of text parts, split by regular expression* $text = $text.substr($beg, $end) # Return the part of text between the start and end index $text = $text.lower() # Return the text with all letters converted to lowercase $text = $text.upper() # Return the text with all letters converted to uppercase $text = $text.trim() # Return the text with no leading nor trailing white space $text = $index.choice($labels) # Return Nth label or argument, eg 'None', 'One', 'Many'
$num = $num.abs() # Return the absolute value of the number $num = $num.pow($exp) # Return the value of the number to the power of exponent $num = $num.round() # Return the rounded number using half-even rounding mode $num = $num.mod($divisor) # Return the remainder of the number divided by the divisor $odd = $num.isOdd() # Return true for odd numbers 1, 3, 5...
$bool = $a == $b # Equals $bool = $a != $b # Not equal $bool = $a < $b # Less Than $bool = $a <= $b # Less than or equal to $bool = $a >= $b # Greater than or equal to $bool = $a > $b # Greater than $bool = $a in $list # Is value in a list $bool = $a notin $list # Is value missing from a list $bool = $a like $wildcard # Like wildcard pattern* $bool = $a notlike $wildcard # Not like wildcard pattern $bool = $a match $regexp # Matches regular expression* $bool = $a notmatch $regexp # Not matches regular expression $bool = $a and $b # && Boolean AND $bool = $a or $b # || Boolean OR $bool = not $a # ! Boolean NOT
$int = $date.year() # Return the year part of the date $int = $date.month() # Return the month part of the date, eg January = 1 $int = $date.day() # Return the day-of-month part of the date $date = $date.addYears($years) # Add the given number of years to the returned date $date = $date.addMonths($months) # Add the given number of months to the returned date $date = $date.addDays($days) # Add the given number of days to the returned date
$int = $dt.epoch() # Return datetime as milliseconds since 1970-01-01 GMT $date = $dt.date($gmt) # Return date in the user time zone (or GMT if arg is true) $time = $dt.time($gmt) # Return time in the user time zone (or GMT if arg is true) $int = $dt.dayOfWeek($gmt) # Return the weekday, eg Monday = 1, Tuesday = 2, etc $text = $dt.format($format, $tz) # Format datetime using a specific format* and time zone
$int = $time.hour() # Return the hour part of the time $int = $time.minute() # Return the minute part of the time $int = $time.second() # Return the second part of the time $int = $time.millis() # Return the millisecond part of the time $time = $time.addHours($hours) # Add the number of hours to the returned time $time = $time.addMinutes($minutes) # Add the number of minutes to the returned time $time = $time.addSeconds($seconds) # Add the number of seconds to the returned time $time = $time.addMillis($millis) # Add the number of milliseconds to the returned time
$id = $id.to18() # Convert the ID to 18 characters $id = $id.to15() # Convert the ID to 15 characters $text = $var.toText() # Convert the variable to a Text value $num = $var.toNumber() # Convert the variable to a Number value $bool = $var.toBoolean() # Convert the variable to a Boolean value $name = $id.idType() # Return the SObject API name for the ID $type = $var.type() # Return type as null, 'Text', 'Number', 'Boolean', 'List', 'Map'
$get = $map.get($key) # Get a value from a map dynamically $put = $map.put($key, $val) # Set a value on the map and return the new value $map = $map.clear() # Remove all the keys and values from the map $copy = $map.clone() # Return a shallow copy of the map $bool = $map.hasKey($key) # Return true if map contains specified key $bool = $map.isEmpty() # Return true if map contains no keys and no values $keys = $map.keys() # Return a list containing all the keys in the map $map = $map.putAll($source) # Copy all keys and values of the source map into the map $val = $map.delete($key) # Delete the map key and return its value $text = $map.toUrl() # Return a URL query string from a map of query parameters $vals = $map.values() # Return a list containing all values in the map
$list = $list.add($item) # Add the item to the end of the list $list = $list.addAll($items) # Add all the items to the end of the list $list = $list.clear() # Remove all items from the list $copy = $list.clone() # Return a shallow copy of the list $bool = $list.hasItem($item) # Return true if the list contains the item $num = $list.indexOf($item) # Return the index of the first occurrence of the item $bool = $list.isEmpty() # Return true if list the has zero items $text = $list.join($separator) # Join the list items into a single text value $item = $list.remove($index) # Removes the item at the index and returns it $num = $list.size() # Return the number of items in the list $list = $list.sort() # Sort the items in the list
Maps associate one or more key-value pairs. A record is an example of a map having many keys (record fields) and associated values. Each value is stored or retrieved using its key. All map keys are text, and map values may consist of any type including another map.
# an empty map $map = { } # a map of currency symbol to exchange rate $gbp_rates = { USD: 1.22, EUR: 1.16, JPY: 167.42 } # store and retrieve map values $gbp_rates.CAD = 1.65 $rate = $gbp_rates.CAD # a map of airline code to airline name $codename = { AA: 'American Airlines' } # put() the key in quotes if it contains numbers or special characters $codename.put('5Y', 'Atlas Air') $codename.put('?', 'Unknown Airline')
Lists are a collection of items. Items in a list may consist of any type including another list. Use the dot . operator to refer to any item by its index. Unlike a map, items in a list are ordered.
# an empty list $list = [ ] # fill a list using a range $letters = 'a'..'z' $daysInJanuary = 1..31 # sort a list of prices $prices = [ 3.50, 1.00, 9.99 ] $prices.sort() # get the first, second, third item in a price list $cheapest = $prices.0 # the index 0 is the 1st in the list $midprice = $prices.1 # the index 1 is the 2nd in the list $expensive = $prices.2 # the index 2 is the 3rd in the list # negative index counts from the end of the list $expensive = $prices.-1 # the index -1 gets the last item $expensive = $prices.get($prices.size - 1) # also gets the last item
Combine lists and maps to model table rows and columns.
# map of prices $plans = { BASIC: 9.00 PREMIUM: 12.50 ENTERPRISE: 20.00 } # list of account records $accounts = [ { Name: 'Dickenson Plc', Code: 'A010', Plan: 'BASIC' } { Name: 'GenePoint', Code: 'A013', Plan: 'PREMIUM' } { Name: 'Grand Hotels', Code: 'A024', Plan: 'ENTERPRISE' } { Name: 'Wide World importers', Code: 'A033', Plan: 'PREMIUM' } ] # a list inside a list represents a table $expectedAnnualRevenues = [ [ $accounts.0.Code, $accounts.0.Plan, $plans.get($accounts.0.Plan) * 12 ] [ $accounts.1.Code, $accounts.1.Plan, $plans.get($accounts.1.Plan) * 12 ] [ $accounts.2.Code, $accounts.2.Plan, $plans.get($accounts.2.Plan) * 12 ] [ $accounts.3.Code, $accounts.3.Plan, $plans.get($accounts.3.Plan) * 12 ] ]
Parameters change a command's behavior. For example, the Http-Post command is affected by its URL, headers, and body. Parameters can be specified by name, or by order.
# Specify each parameter name followed by its value Http-Post -url 'example.com' -headers {Cookie:null} -body 'data' # Alternatively, specify just the values (in the correct order) Http-Post 'example.com' {Cookie:null} 'data'
Flags are parameters that have no value. The presence (or not) of a flag affects the command. For example Datetime has a -GMT flag. Flag parameters may appear in any order.
# one second before Christmas in GMT time zone Datetime-Value 2022 12 24 23 59 59 -gmt # one second before Christmas, user time zone Datetime-Value 2022 12 24 23 59 59
Aliases are shortcuts to a command that can make logic less verbose. The alias reduces a command to one word and does not affect its behavior.
# one second before Christmas, user time
Datetime 2022 12 24 23 59 59
A logic block ${...} is a mini procedure that alters how a command runs. For example:
Here is a logic block ${...}
appearing as a parameter on the Enqueue command:
Logic blocks are similar to JavaScript lambdas or arrow functions and come in two forms.
${
then many statements followed by a return }
# Block form Enqueue ${ Http-Post 'api.example.com' # async callout }
Try# Concise form $sunday = 1 # where booking date falls on a sunday $dates = [ '2022-12-10', '2022-12-11', '2022-12-12' ] $sundays = Filter $dates $_.dayOfWeek.eq($sunday) # concise logic omits the curly braces
Logic blocks can make business logic more readable. Meaningful comments and variable names help too. These two examples produce the same result but in different ways:
Try# Logic block - find odd numbers $odds = Filter [1, 2, 3, 4, 5] $_.isOdd
Try# Foreach Loop - find odd numbers (same result) $odds = [] foreach ($item in [1, 2, 3, 4, 5]) { if ($item.isOdd) { $odds.add($item) } }
Like an anonymous callback, commands may accept values for use inside the logic.
$values
collection then avail each item as $_
$value
availed in the logic as $_
Try# Required values - each item availed to logic $values = [1, 2, 3, 4, 5] $odds = Filter $values $_.isOdd
# Optional value - availed to logic Enqueue $value ${ Http-Post 'api.example.com' -body $_ }
Advanced example - sort a list of nested maps
This specifies a primary order and secondary order using the special $_
variable twice:
$list_applications = [ { Course: 'Postgrad', Student: {Score: 80, Name: 'Tom'} } { Course: 'Undergrad', Student: {Score: 60, Name: 'Liz'} } { Course: 'Postgrad', Student: {Score: 70, Name: 'Jim'} } { Course: 'Undergrad', Student: {Score: 90, Name: 'Bob'} } ] # Sort by course then by score (note the concise logic) $by_course_score = Sort $list_applications [ $_.Course, $_.Student.Score ]
Result: [
{ Course: 'Postgrad', Student: {Score: 70, Name: 'Jim'} }
{ Course: 'Postgrad', Student: {Score: 80, Name: 'Tom'} }
{ Course: 'Undergrad', Student: {Score: 60, Name: 'Liz'} }
{ Course: 'Undergrad', Student: {Score: 90, Name: 'Bob'} }
]
Pipes are commands chained together using the pipe |
operator. Pipes feed the data from the left of the pipe | operator into the command on the right. When the data is a list, the command acts on each item one by one. Use pipes to transform and combine lists and maps.
Try# european taxes $eu_taxes = [ 20, 21, 20, 19, 21, 19, 25, 20, 24, 21, 24, 20, 25, 27, 23, 22, 21, 17, 21, 18, 21, 23, 23, 19, 25, 22, 20] # the top three european taxes are 27%, 25%, 24% $top_taxes = $eu_taxes | Unique | Sort | Reverse | Top 3
Special $_ variable refers to the current value being worked on.
$_
refers to the state value$_
refers to the decision value$_
refers to the error message$_
refers to the current list item, $__
is the index$_
is the map value, double $__
is the map keyHere is another example with logic blocks, the special variable, pipes and commands. Each list item feeds into the command after a pipe. $_ is the current item being worked on.
# Debit lines used to create an accounting journal $debits = [ {Code: 'Rent', Amount: 8800} {Code: 'Heat', Amount: 1100} ] # Pipe Approach - create journal $credits = $debits | Copy | Apply ${ $_.Amount *= -1 } | Apply ${ $_.Code = 'Bank'} $journal = $credits + $debits # Loop Approach - create journal (same result) $journal = [] foreach ($debit in $debits) { $credit = $debit.clone() $credit.Amount *= -1 $credit.Code = 'Bank' $journal.add($credit) $journal.add($debit) } # net balance $balance = Sum $journal $_.Amount Log $balance # zero
Functions are blocks of re-usable logic. For example, a function can be written to retrieve one exchange rate, then it can be generalized and re-used to retrieve different rates.
Use parentheses after the function name to define comma separated parameters. Use return to hand back the function results. Think of a function as your own custom command.
Tryfunction Calculate-Age($birthdate) { $today = Script-Today return $today.year - $birthdate.year } # use the function as you would use a command $age = Calculate-Age '1991-02-17' Log `Edward Sheeran is $age years old`
Errors happen when you try something bad, like dividing by zero. If that happens, catch the error and supply logic to report it, or choose to do something else instead.
Put your happy path logic in a try block, and your error handling logic in a catch block. If an error occurs, the special $_ variable holds the error detail. This is known as an exception.
Trytry { $discount = ($listPrice - $salePrice) / $listPrice } catch { throw `Cannot calculate discount: $_` }
Optionally, the throw keyword allows you to raise your own error with your own message.
Streamscript supports the use of binary data. To use binary data in HTTP requests and HTTP responses, use the -base64 flag when running HTTP commands. This flag treats both the request and response body as base64 encoded binary data.
In this example, a PDF invoice is retrieved. The PDF body is stored on the Document Body field as-is, because it was already encoded by the HTTP command using the -base64 flag. Return the $Document record so that Flow Builder can insert it.
# get pdf invoice, base64 encoded $url = 'isaw.nyu.edu/guide/forms/sample-vendor-invoice' $pdf = Http-Get $url -base64 # new record $Document = New-Document { Name = 'inv.pdf' Body = $pdf.body } # output as SObject return $DocumentTry
Alternatively you can store and retrieve plain text in blob fields like Document Body, so long as the Base64-Encode command is used to encode the stored text, or use Base64-Decode to retrieve a binary field back as text.
Directives must occupy the first line of the script in the form of a comment, for example:
In bulk mode your script will be executed exactly once even though there may be more than one initiating request. For this reason, you must treat merge fields as lists, and you must return a corresponding list. Example:
# Streamscript Bulk $accounts = {!$Record} $size = $accounts.size() # retrieve many cat facts in one callout $http = Http-Get `catfact.ninja/facts?limit=$size` $result = Json-Decode $http.body $facts = $result.data # put each cat fact on each account for ($i = 0; $i < $size; $i++) { # use the same list index $fact = $facts.get($i) $acct = $accounts.get($i) $acct.Description = `$fact` }
When making callouts, we recommend:
- Enable Lightning runtime for flows: Setup > Process Automation Settings
- For screen flows, check: Always start a new transaction (on the step, under advanced)
- For record-triggered flows, check: Run Asynchronously path to access an external system
after the original transaction for the triggering record is successfully committed.
Webhooks are flows that are triggered in response to web requests, as opposed to record changes. With a webhook, data is received from an external application at a site belonging to your Salesforce instance. When events arrive at your URL, the associated flow is triggered with access to the data sent from the external system.
Follow the site setup video then visit the Integrations tab to handle webhooks:
Read the request data from the $Webhook request properties:
Try$Webhook.request # Request body $Webhook.requestIp # IP address $Webhook.requestUri # Resource URI $Webhook.requestPath # Path starting with / $Webhook.requestMethod # HTTP request method $Webhook.requestParams # Map of URL parameters $Webhook.requestHeaders # Map of HTTP request headers
Write the response data to the $Webhook response properties:
$Webhook.response # Response body $Webhook.responseStatus # HTTP status code $Webhook.responseHeaders # Map of HTTP response headers
Don't overwrite the $Webhook.responseHeaders variable. Add values to the map like this: $Webhook.responseHeaders.Content-Type = 'text/xml'
Mailhooks are flows triggered by inbound emails. With a mailhook, data is received at an email services address belonging to your Salesforce instance. The associated flow is triggered with access to the email payload and any attachments. All email service attributes such as bounces and addresses, running user context and SPF, are configurable after deploying a mailhook.
Read the email data from the $Mailhook properties:
$Mailhook.subject # Text of the subject $Mailhook.replyTo # Reply-To header text $Mailhook.fromName # Name from the From header $Mailhook.fromAddress # Address from the From header $Mailhook.toAddresses # List of To addresses $Mailhook.ccAddresses # List of CC addresses $Mailhook.plainTextBody # Plain text email body $Mailhook.htmlBody # HTML version of the email $Mailhook.messageId # This message ID as text $Mailhook.inReplyTo # Parent message ID text $Mailhook.references # List of thread references $Mailhook.headers # Map of RFC 2822 header values $Mailhook.textAttachments # List of text files, eg CSV $Mailhook.binaryAttachments # List of binary files, eg PNGTry
Write an optional result to the $Mailhook message and success properties:
$Mailhook.message # Text to return in the body of a reply $Mailhook.success # False to reject the inbound email
Mailhooks are also called inbound email handlers, Email to Flow, Email-to-Case, or email2flow.
Dates and times always use ISO-8601. To display any other format, use the format() method.
# ISO-8601 $date = '2022-12-24' $time = '23:59:59.999Z' $datetime = '2022-12-24T23:59:59.999Z' $ddMMyyyy = $datetime.format('dd/MM/yyyy') # 24/12/2022
Example Format | Example Result |
---|---|
"yyyy.MM.dd G 'at' HH:mm:ss z" | 2001.07.04 AD at 12:08:56 PDT |
"EEE, MMM d, ''yy" | Wed, Jul 4, '01 |
"h:mm a" | 12:08 PM |
"hh 'o''clock' a, zzzz" | 12 o'clock PM, Pacific Daylight Time |
"K:mm a, z" | 0:08 PM, PDT |
"yyyyy.MMMMM.dd GGG hh:mm aaa" | 2001.July.04 AD 12:08 PM |
"EEE, d MMM yyyy HH:mm:ss Z" | Wed, 4 Jul 2001 12:08:56 -0700 |
"yyMMddHHmmssZ" | 010704120856-0700 |
"yyyy-MM-dd'T'HH:mm:ss.SSSZ" | 2001-07-03T12:08:56.235-0700 |
"yyyy-MM-dd'T'HH:mm:ss.SSSXXX" | 2001-07-03T12:08:56.235-07:00 |
"YYYY-'W'ww-u" | 2001-W27-3 |
Letter | Component | Presentation | Examples |
---|---|---|---|
G | Era designator | Text | AD |
y | Year | Year | 1996; 96 |
Y | Week year | Year | 2009; 09 |
M | Month in year | Month | July; Jul; 07 |
w | Week in year | Number | 27 |
W | Week in month | Number | 2 |
D | Day in year | Number | 189 |
d | Day in month | Number | 10 |
F | Day of week in month | Number | 2 |
E | Day name in week | Text | Tuesday; Tue |
u | Day number (1 = Monday, 7 = Sunday) | Number | 1 |
a | Am/pm marker | Text | PM |
H | Hour in day (0-23) | Number | 0 |
k | Hour in day (1-24) | Number | 24 |
K | Hour in am/pm (0-11) | Number | 0 |
h | Hour in am/pm (1-12) | Number | 12 |
m | Minute in hour | Number | 30 |
s | Second in minute | Number | 55 |
S | Millisecond | Number | 978 |
z | Time zone | General time zone | Pacific Standard Time; PST; GMT-08:00 |
Z | Time zone | RFC 822 time zone | -0800 |
X | Time zone | ISO 8601 time zone | -08; -0800; -08:00 |
Streamscript uses regular expressions to split and match.
# does a text value match the phone number format '408-971-2288' match '^\b\d{3}[-.]?\d{3}[-.]?\d{4}\b$' # true # extract text items separated by numbers 'aaa123bbb456ccc789'.split('\d+') # ["aaa","bbb","ccc"]
Regex Basics | Description |
---|---|
^ | The start of a string |
$ | The end of a string |
. | Wildcard which matches any character, except newline (\n). |
| | Matches specific character(s) on either side, eg a|b corresponds to a or b |
\ | Used to escape a special character |
a | The character "a" |
ab | The string "ab" |
Quantifiers | Description |
---|---|
* | Used to match 0 or more of the previous (e.g. xy*z could correspond to "xz", "xyz" etc.) |
? | Matches 0 or 1 of the previous |
+ | Matches 1 or more of the previous |
{5} | Matches exactly 5 |
{5, 10} | Matches everything between 5-10 |
Character | Description |
---|---|
\s | Matches a whitespace character |
\S | Matches a non-whitespace character |
\w | Matches a word character |
\W | Matches a non-word character |
\d | Matches one digit |
\D | Matches one non-digit |
[\b] | A backspace character |
\c | A control character |
Special | Description |
---|---|
\n | Matches a newline |
\t | Matches a tab |
\r | Matches a carriage return |
\ZZZ | Matches octal character ZZZ |
\xZZ | Matches hex character ZZ |
\0 | A null character |
\v | A vertical tab |
Groups | Description |
---|---|
(xyz) | Grouping of characters |
(?:xyz) | Non-capturing group of characters |
[xyz] | Matches a range of characters (e.g. x or y or z) |
[^xyz] | Matches a character other than x or y or z |
[a-q] | Matches a character from within a specified range |
[0-7] | Matches a digit from within a specified range |
Use a template containing wildcard and the like or notlike method to match text
'1234'.like('_23_') # true
Wildcard | Description |
---|---|
_ | a placeholder representing any character |
% | a placeholder representing any character, any number of times |
Boolean Operators | Description |
---|---|
== | Equals |
!= | Not equal |
< | Less Than |
<= | Less than or equal to |
>= | Greater than or equal to |
> | Greater than |
in | Is value in a list |
notin | Is value missing from a list |
like | Like wildcard pattern |
notlike | Not like wildcard pattern |
match | Matches regular expression |
notmatch | Not matches regular expression |
&& | Boolean AND |
|| | Boolean OR |
! | Boolean NOT |
Math Operators | Description |
---|---|
.. | Range |
= | Assignment |
* | Multiplier |
^ | Power |
/ | Division |
% | Modulus |
+ | Addition |
- | Subtraction |
*= | Multiply then assign |
/= | Division then assign |
%= | Remainder then assign |
+= | Addition then assign |
-= | Subtraction then assign |
Other Operators | Description |
---|---|
++ | Increment |
-- | Decrement |
| | Pipe |
? : | Ternary |
Global variables may be used in a script via Merge Field syntax.
$Account = {!$Record} # map
Record Resources | Data Type |
---|---|
$Record | SObject |
$Record__Prior | SObject |
Flow Resources | |||
---|---|---|---|
$Flow.CurrentDate | Date | $Flow.InterviewStartTime | DateTime |
$Flow.CurrentDateTime | DateTime | $Flow.ActiveStages | String |
$Flow.FaultMessage | String | $Flow.InterviewGuid | String |
$Flow.CurrentStage | String | $Flow.CurrentRecord | String |
Organization Resources | |||
---|---|---|---|
$Organization.City | String | $Organization.Longitude | Number |
$Organization.Country | String | $Organization.Name | String |
$Organization.Division | String | $Organization.Phone | String |
$Organization.Fax | String | $Organization.PostalCode | String |
$Organization.GeocodeAccuracy | String | $Organization.State | String |
$Organization.Id | String | $Organization.Street | String |
$Organization.Latitude | Number | $Organization.UiSkin | String |
Profile Resources | |||
---|---|---|---|
$Profile.LastModifiedDate | DateTime | $Profile.CreatedById | String |
$Profile.ManageUsers | Boolean | $Profile.CreatedDate | DateTime |
$Profile.Name | String | $Profile.Description | String |
$Profile.UsageType | String | $Profile.Id | String |
$Profile.UserType | String | $Profile.LastModifiedById | String |
User Resources | |||
---|---|---|---|
$User.Alias | String | $User.Latitude | Number |
$User.City | String | $User.LocaleSidKey | String |
$User.CommunityNickname | String | $User.Longitude | Number |
$User.CompanyName | String | $User.ManagerId | String |
$User.ContactId | String | $User.MobilePhone | String |
$User.Country | String | $User.Phone | String |
$User.Department | String | $User.PostalCode | String |
$User.Email | String | $User.ProfileId | String |
$User.EmployeeNumber | String | $User.Signature | String |
$User.EndDay | String | $User.StartDay | String |
$User.Extension | String | $User.State | String |
$User.Fax | String | $User.Street | String |
$User.FederationIdentifier | String | $User.TimeZoneSidKey | String |
$User.FirstName | String | $User.Title | String |
$User.GeocodeAccuracy | String | $User.UITheme | String |
$User.Id | String | $User.UIThemeDisplayed | String |
$User.IsActive | Boolean | $User.Username | String |
$User.LanguageLocaleKey | String | $User.UserRoleId | String |
$User.LastName | String | $User.UserType | String |
User Role Resources | |||
---|---|---|---|
$UserRole.CaseAccessForAccountOwner | String | $UserRole.MayForecastManagerShare | Boolean |
$UserRole.ContactAccessForAccountOwner | String | $UserRole.Name | String |
$UserRole.DeveloperName | String | $UserRole.OpportunityAccessForAccountOwner | String |
$UserRole.Id | String | $UserRole.PortalRole | String |
$UserRole.LastModifiedById | String | $UserRole.PortalType | String |
$UserRole.LastModifiedDate | DateTime | $UserRole.RollupDescription | String |
Getting started with Streamscript
Install from the Salesforce AppExchange
Package install link: /packaging/installPackage.apexp?p0=04tGA000005NDq5
Webhooks in Flow |
Streamscript Playground |