> ## Documentation Index
> Fetch the complete documentation index at: https://docs.m3ter.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Generic m3ter API Invocable Action

The m3ter Connector for Salesforce managed package offers the *Generic m3ter API Invocable Action* feature that lets admins and developers call any Organization-scoped m3ter API endpoint from Salesforce — Apex or Flow — reusing the package's existing authentication, retry, and telemetry:

* **Admins**. Automate m3ter from Flow without waiting on a developer.
* **System Integrators**. Offers a supported, reusable primitive to build customer solutions on, instead of hand-rolling callouts every time.

If there isn't a dedicated action for what you need yet, you can now do it yourself:

* Call any m3ter endpoint from Flow/Apex.
* Pull values out of responses without writing Apex.
* Ready-to-clone example flows so teams start from something that works, not a blank canvas

This topic introduces and explains how to work with the Generic m3ter API Invocable Action feature:

* [Key Components](#key-components)
* [Prerequisites](#prerequisites)
* [Organization-Scoped Endpoint Paths](#organization-scoped-endpoint-paths)
* [Apex and Flow Examples](#apex-and-flow-examples)
* [Limits](#limits)
* [Sync Logs and External Mappings](#sync-logs-and-external-mappings)

<Warning>
  **Important!**

  * **Check Version**. The *Generic m3ter API Invocable Action* feature described in this topic is only available in **v1.2** and above of the m3ter Connector for Salesforce. See [m3ter Connector for Salesforce - Changelog](https://docs.m3ter.com/guides/m3ter-connector-for-salesforce/m3ter-connector-for-salesforce-changelog) for details on how to check your current installed version.
</Warning>

## Key Components

| Component                                     | Type             | Purpose                                                                                           |
| --------------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------- |
| M3terGenericAPIService                        | Apex + Invocable | Transport — call any endpoint (GET/POST/PUT/DELETE)                                               |
| M3terJsonExtractInvocable                     | Invocable        | No-code helper — pull values out of a JSON response by path                                       |
| M3terAccountParserExample                     | Apex example     | **Read** (GET): `GET accounts/{id}` → typed Flow fields                                           |
| M3terCreateProductExample                     | Apex example     | **Create** (POST): `POST products` → new m3ter id                                                 |
| M3terListAccountsExample                      | Apex example     | **List + pagination**: pages `GET accounts` via `nextToken`                                       |
| M3terListOptionsExample                       | Apex example     | **Choice-list builder**: pages a list endpoint into `{label, value}` options for a Flow drop-down |
| m3ter Example: Create Balance and Transaction | Flow example     | **Dependent-entity chain**: create a Balance, then a Transaction against it                       |
| m3ter Example: Create Segment Pricing         | Flow example     | **Read-then-write on segmented entities**: read an Aggregation's segments, then create a Pricing  |

Notes:

* The example classes and Flows are **copy-and-adapt templates** — one per operation/pattern.
* To adapt: change the endpoint/operation, and map the fields you need from the response.

## Prerequisites

Please ensure the following prerequisites are in place before using the Generic m3ter API Invocable Action feature:

* The **m3 Sync** package is installed and configured (Access Key, API Secret, Base URL, Organization Id) in **Integration Settings**.
* Users are assigned the **m3ter\_Admin** or **m3ter\_User** permission set.

## Organization-Scoped Endpoint Paths

Main points to note:

* Supply the path **relative to your m3ter Organization**:
  * The service prefixes `https://<baseUrl>/organizations/<orgId>/`
  * So for example for accounts: `.../organizations/<orgId>/accounts`
* Root-level endpoints - for example: `/organizationconfig`, `/oauth` - are **not** supported.
* Supported operations: **GET, POST, PUT, DELETE**.
* The canonical list of endpoints and payloads can be found in the m3ter API Reference documentation at: [<u>https://docs.m3ter.com/</u>](https://docs.m3ter.com/)

## Apex and Flow Examples

This section sets out some Apex and Flow examples using the Generic m3ter API Invocable Action feature:

* [Apex Usage Example](#apex-usage-example)
* [Apex Usage Complex Example](#apex-usage-complex-example)
* [Flow Usage](#flow-usage)

### Apex Usage Example

Apex:

```java theme={null}
m3.M3terGenericAPIService.GenericAPIRequest request = new m3.M3terGenericAPIService.GenericAPIRequest();
request.operation = 'GET';
request.endpoint = 'accounts';
request.queryParams = '{"pageSize":"50"}';   // optional, JSON object of string values

List<m3.M3terGenericAPIService.APITransportResult> results =
    m3.M3terGenericAPIService.callM3terAPI(
        new List<m3.M3terGenericAPIService.GenericAPIRequest>{ request }
    );

m3.M3terGenericAPIService.APITransportResult result = results[0];
if (result.success) {
    Map<String, Object> body = (Map<String, Object>) JSON.deserializeUntyped(result.responseBody);
    if (result.hasMoreResults) { /* result.nextToken */ }
} else {
    // result.httpStatusCode, result.errorMessage
}
```

**GenericAPIRequest:** 

* operation (required), 
* endpoint (required), 
* queryParams (optional JSON object of string values), 
* requestBody (optional JSON body for POST/PUT).

**APITransportResult:** 

* success, 
* httpStatusCode, 
* responseBody, 
* errorMessage, 
* nextToken, 
* hasMoreResults.

### Apex Usage Complex Example

Apex:

```java theme={null}
//Create an m3ter Balance for an Account, then post a Transaction against it 

String accountId    = 'bfc500d9-0427-4d80-9ddb-03e6140970dc';
String currencyCode = 'USD';
String startDate    = '2026-01-01T00:00:00.000Z';
String endDate      = '2026-12-31T00:00:00.000Z';
Decimal initialAmount = 1000;

// ── Step 1: create the Balance 
m3.M3terGenericAPIService.GenericAPIRequest balanceReq =
    new m3.M3terGenericAPIService.GenericAPIRequest();
balanceReq.operation = 'POST';
balanceReq.endpoint = 'balances';
String balanceCode = System.UUID.randomUUID().toString();
balanceReq.requestBody = JSON.serialize(new Map<String, Object>{
    'accountId'   => accountId,
    'currency'    => currencyCode,
    'startDate'   => startDate,
    'endDate'     => endDate,
    'code'        => balanceCode,
    'name'        => 'Prepaid balance created via generic API service'
});

m3.M3terGenericAPIService.APITransportResult balanceRes =
    m3.M3terGenericAPIService.callM3terAPI(
        new List<m3.M3terGenericAPIService.GenericAPIRequest>{ balanceReq }
    )[0];

if (!balanceRes.success) {
    System.debug(LoggingLevel.ERROR,
        'Balance create failed (' + balanceRes.httpStatusCode + '): ' + balanceRes.errorMessage);
    return;
}

Map<String, Object> balanceBody =
    (Map<String, Object>) JSON.deserializeUntyped(balanceRes.responseBody);
String balanceId = (String) balanceBody.get('id');
System.debug('Created Balance: ' + balanceId);

// Step 2: post a Transaction against the new Balance 
// The endpoint is built from the id returned by Step 1 

m3.M3terGenericAPIService.GenericAPIRequest txReq =
    new m3.M3terGenericAPIService.GenericAPIRequest();
txReq.operation = 'POST';
txReq.endpoint = 'balances/' + balanceId + '/transactions';
txReq.requestBody = JSON.serialize(new Map<String, Object>{
    'amount'      => initialAmount,
    'appliedDate' => startDate,
    'currencyPaid'=> currencyCode,
    'transactionTypeId' => 'ca6af083-c94b-47a8-832f-22f17dba7267',    
    'description' => 'Initial funding'
});

m3.M3terGenericAPIService.APITransportResult txRes =
    m3.M3terGenericAPIService.callM3terAPI(
        new List<m3.M3terGenericAPIService.GenericAPIRequest>{ txReq }
    )[0];

if (!txRes.success) {
    // Balance exists but the transaction failed — retry the transaction against
    // balanceId rather than re-creating the balance (that would orphan one in m3ter).
    System.debug(LoggingLevel.ERROR,
        'Balance ' + balanceId + ' created, but transaction failed (' +
        txRes.httpStatusCode + '): ' + txRes.errorMessage);
    return;
}

Map<String, Object> txBody =
    (Map<String, Object>) JSON.deserializeUntyped(txRes.responseBody);
System.debug('Created Transaction: ' + txBody.get('id') + ' against Balance ' + balanceId);
```

### Flow Usage

Two-action pattern:

1. **Call m3ter API** (M3terGenericAPIService) — set *Operation* and *Endpoint*; outputs Response Body, Success, HTTP Status Code, Next Token, Has More Results.
2. **Extract m3ter JSON Fields** (M3terJsonExtractInvocable) — optional; pull values out of the response by *Paths* (e.g. \["data\[0].name", "data\[0].address.locality"]). Object keys and array indexes are supported; an unmatched path returns null.
   * **Values** — one entry per input path, in order.
   * **Element Values** — when a path resolves to a JSON *array*, its elements are returned here so you can **loop over the array in Flow**.

Branch on `{!Call_m3ter_API.success}` and surface `{!Call_m3ter_API.errorMessage}` on failure.

See the two shipped example Flows for working patterns: dependent-entity chaining, dynamic-choice-set drop-downs bound to M3terListOptionsExample, product-filtered lists, looping over segmented fields, and assembling a JSON request body from a Formula.

## Limits

Note the following limitations:

* **Synchronous callout** in the current transaction. Because of Salesforce's "no callout after DML" rule, do **not** perform DML *before* this action in the same transaction/Flow run — do all callouts first and DML last, or split across transactions.
* Up to **100 callouts per transaction**; request/response bodies bounded by the **6 MB** heap limit; 120s callout timeout.
* Errors never throw out of the invocables — you must check **success / errorMessage**.

## Sync Logs and External Mappings

The Generic m3ter API Invocable Action feature is a **raw pass-through** service — it deliberately does **less** than the standard sync actions (Sync to m3ter, etc.), and you own the difference:

* **No Sync Logs.** Calls do not create **SyncLog\_\_c** or **SubmitSnapshot\_\_c** records. If you need an audit trail, you must log it yourself after the call.
* **Not external-mapping aware.** Performing a create through this service makes a brand-new m3ter entity with **no Salesforce ↔ m3ter link**, so the package's sync features won't reconcile it and repeat calls create duplicates. If linkage matters, prefer the standard **Sync to m3ter** action; otherwise keep your own calls idempotent (look up before create) and maintain the link via the externalmappings endpoint yourself. See [<u>https://docs.m3ter.com/</u>](https://docs.m3ter.com/).
