Salesforce Custom REST API Endpoint Caller
Salesforce action: SendHTTPRequest. Generic reusable flow that accepts a REST endpoint path, HTTP method, and body as parameters, calls any Salesforce REST API (including custom Apex endpoints), and writes the response to a Dataverse log table.
Provided as-is, without warranty of any kind. Review and test each pattern in a non-production environment before deploying it to live automations. See our Terms.
Overview
A generic, reusable Power Automate cloud flow that acts as a thin wrapper around the Salesforce connector's HttpRequest action. It accepts a REST endpoint path, HTTP method, and optional JSON body as manual trigger inputs, calls any Salesforce REST API (standard, Apex, Chatter, Bulk, Metadata, Tooling, Analytics), and writes a full audit record of the call to a Dataverse log table.
Because the Salesforce connector handles authentication, this flow can call any Salesforce REST endpoint without ever embedding OAuth tokens, session IDs, or security tokens in the flow definition. It turns Power Automate into a zero-config "Salesforce REST console."
Use Case
Every call is logged to a Dataverse table — endpoint, method, request body, response body, status code, timestamp — giving you an audit history without instrumenting individual flows.
The flow is ideal for teams that:
- Custom Apex REST endpoints — call /services/apexrest/MyService/doWork without building a dedicated flow per service.
- Connector gap-filling — hit any REST API the Salesforce connector doesn't expose as a first-class operation (Metadata API, Tooling API, Chatter, Analytics, Bulk v2).
- Ad-hoc admin queries — run arbitrary SOQL via /services/data/{v}/query?q=... when you don't want to build a flow around one-off data pulls.
- Diagnostic tooling — support engineers can POST to /services/data/{v}/sobjects/... to repair records with a full audit trail, instead of logging into Salesforce directly.
- Integration prototyping — quickly test the shape of a Salesforce API response before wiring it into a larger flow.
Flow Architecture
Manually trigger a flow
Manual (Button / Request) triggerThree inputs: Endpoint_Path (required string — Salesforce REST path starting with `/`, e.g. `/services/data/v60.0/sobjects/Account/0011x000004XXXXX` or `/services/data/v60.0/query?q=SELECT+Id+FROM+Account+LIMIT+10`), HTTP_Method (required string — one of `GET`, `POST`, `PATCH`, `PUT`, `DELETE`), Request_Body (optional string — JSON body for `POST`/`PATCH`/`PUT`; leave empty for `GET`/`DELETE`).
Initialize varApiVersion
Initialize variableSets `varApiVersion` from env var `flowlibs_SalesforceRestApiVersion` (default `v60.0`). Documented for callers building their own endpoint paths. Runs in parallel with the other four init-variable actions directly off the trigger.
Initialize varLogTableName
Initialize variableSets `varLogTableName` from env var `flowlibs_SalesforceRestLogTable` (default `flowlibs_salesforcerestcalllogs`). Documentation reference; the `CreateRecord` action hardcodes the entity name so the designer can resolve the column schema.
Initialize varEndpoint
Initialize variableSets `varEndpoint` to `triggerBody()?['text']` — the endpoint path supplied by the caller.
Initialize varMethod
Initialize variableSets `varMethod` to `toUpper(triggerBody()?['text_1'])` — the HTTP method, normalized to uppercase so Salesforce doesn't reject lower-case verbs.
Initialize varRequestBody
Initialize variableSets `varRequestBody` to `coalesce(triggerBody()?['text_2'], '')` — the optional JSON body, defaulted to empty string for GET/DELETE calls.
Call_Salesforce_Rest_Api
Salesforce — HttpRequestRuns after all five init-variable actions succeed (parallel-to-join). Passes `Uri: @variables('varEndpoint')`, `Method: @variables('varMethod')`, `Body: @variables('varRequestBody')`, `ContentType: application/json`. Authentication and session handling are managed by the Salesforce connector — no tokens embedded in the flow.
Environment Variables
| Schema name | Type | Default | Description |
|---|---|---|---|
| flowlibs_SalesforceRestApiVersion | String | v60.0 | Documents the REST API version callers should use when constructing endpoint paths. Change per org. |
| flowlibs_SalesforceRestLogTable | String | flowlibs_salesforcerestcalllogs | Entity set name of the Dataverse audit log table written to by Log_Call_To_Dataverse. |
Connectors & Connections
| Connector | API name | Actions used |
|---|---|---|
| Salesforce | shared_salesforce | HttpRequest (primary action — calls any Salesforce REST endpoint) |
| Microsoft Dataverse | shared_commondataserviceforapps | CreateRecord (writes the audit log row) |
Note — All connections are referenced as solution connection references; the flow is portable between environments as long as a connection is mapped at import time.
Customization Guide
Almost every realistic variant of this flow can be implemented by changing environment variable values. A few cases require small edits inside the flow definition — those are called out explicitly below.
- Change the Salesforce API version
- Update the default value of flowlibs_SalesforceRestApiVersion in each environment where the solution is imported. Callers are responsible for embedding the version in their endpoint paths; the variable exists as a documented anchor.
- Log failures as well as successes
- Change the Log_Call_To_Dataverse action's runAfter clause to include Failed, and swap the status code expression for one that reads from the error output when the call fails.
- Add header support
- The Salesforce connector's HttpRequest operation exposes a Headers parameter. Wire a fourth trigger input or a variable to pass custom headers (e.g. Sforce-Auto-Assign: FALSE, or a custom locale).
- Return the response to the caller
- Append a Response (HTTP response) action that returns outputs('Call_Salesforce_Rest_Api')?['body'] with status @{outputs('Call_Salesforce_Rest_Api')?['statusCode']}. This lets you wrap the flow as a callable HTTP endpoint.
- Restrict who can call arbitrary endpoints
- A button trigger is only as secure as the people with access to run it. For untrusted callers, replace the manual trigger with a solution-aware HTTP trigger and validate the incoming method/endpoint against an allowlist before the Salesforce call.
- Extend the log schema
- Add columns for CalledByUser (bound to @{triggerOutputs()?['headers']?['x-ms-user-email-encoded']}) or CorrelationId for cross-system tracing.
Key Expressions
The flow is intentionally light on Power Fx / WDL gymnastics — the heaviest expressions are the branch-name concatenation and the approval outcome check. They are listed below in the order they appear in the flow.
EXPR.01Read trigger inputs
Pull the three manual-trigger inputs (Endpoint_Path, HTTP_Method, Request_Body respectively).
EXPR.02Normalize HTTP method
Uppercase the HTTP method so Salesforce doesn't reject `get` / `Post`.
EXPR.03Default optional request body
Defaults the optional Request_Body to an empty string so GET/DELETE calls don't fail on null handling downstream.
EXPR.04Truncate response to Dataverse memo cap
Stringifies and caps the response to fit the Dataverse memo limit (100,000 characters).
EXPR.05Defensive status code read
Reads the status code with a 200 fallback to avoid null-writes when the connector omits it on empty responses.
EXPR.06Audit record primary name
Builds the audit record's primary name so the log is easy to scan in a Dataverse view.
Comments
Sign in to join the conversation.
Sign inNo comments yet. Be the first to share your experience with this flow.