# Macro API V3

A **macro** is a saved bundle of actions that runs against an entity in a single step. Macros execute multiple actions on an entity with a single click and can be used to make multiple changes to entities at once, creating efficiencies in your workflows. A macro can be applied to a range of assets and can be configured with a number of actions, depending on the asset type.

The **Macro API** invokes a saved macro programmatically. Use it to apply macros to Cases, Outbound Messages, User-Generated Content, Profiles, Campaigns, Tasks, Sub-Campaigns, Media Assets, and Social Accounts.

## Overview

| Operation | Method | Path |
|  --- | --- | --- |
| Apply macro(s) | `POST` | `/api/v3/macro/apply` |


**Benefits:**

- **Automate macro application** — apply macros to Cases, Profiles, UGC, Campaigns, Outbound Messages, Tasks, Sub-Campaigns, Media Assets, and Social Accounts without manual intervention.
- **Boost productivity** — reduce manual effort and enhance agent productivity.
- **Enable complex automation** — trigger multi-step action sets across the supported entity types from your own systems.


### The division of labour

This is the key mental model, and it explains why the request body is so small:

```
Sprinklr UI  →  defines WHAT the macro does    (the actions, configured once by an admin)
Macro API    →  defines WHEN and WHERE it runs (which entities, triggered by your system)
```

The API carries **no action payload**. It sends three things: what kind of entity (`assetClass`), which entities (`entityKeys`), and which macros (`macroIds`). Everything the macro actually *does* was decided when an admin built it in the UI. You cannot construct, alter, or parameterise an action through this endpoint.

> **The behaviour of your integration can change without any code change on your side.** If an admin edits the macro, your next call does something different. Treat macro IDs as a shared contract with your Sprinklr admins, and document which macro each configured ID refers to.


### Prerequisite: the macro must exist in the UI

You cannot create a macro through this API. An admin builds it first:

1. Click the **New Tab** icon. Under **Platform modules**, click **Macros** within settings.
2. In the top-right corner of the Macros window, click **Create Macro**.
3. Enter a **Macro Name** and **Description**, and select the entity to apply the macro to from the **Apply macro on** dropdown.
4. Set actions under **Automated Actions** and **Manual Actions**.
5. Select visibility preferences — all workspaces, specific workspaces, or specific users.
6. Click **Save**.


The entity types available in that dropdown are **Inbound Message, Outbound Message, SAM Asset, Case, UGC Asset, Profile, Task, Campaign, Sub-campaign, and User**. The macro you build is bound to one entity type, and that binding must match the `assetClass` you send.

Two configuration settings materially affect API behaviour — check them with your admin before integrating:

- **"Ask user for confirmation before applying this macro"** — designed for an interactive UI flow.
- **Manual Actions** — you are asked to add or edit selected inputs whenever the macro is applied. The `/macro/apply` request body has no field for supplying those inputs, so prefer macros built entirely from **Automated Actions** for API-driven use.


> **Macros are workspace-scoped.** Macros can be viewed, edited, and created by admins from Settings, and are available at the Workspace level only. A macro ID that resolves in one workspace may not resolve in another, and visibility rules restrict which users can apply it. If your API user cannot see the macro, the call fails.


### Obtaining macro IDs

Macro IDs are obtained from the Sprinklr UI by an admin and stored in your configuration. Plan for that as a setup step, and treat a configured macro ID as a dependency that fails at runtime with a `404` if the macro is later deleted.

## Base URL

```
https://api3.sprinklr.com/{env}/api/v3/macro/apply
```

Replace `{env}` with your assigned environment identifier: `prod`, `prod0`, `prod2`, `prod3`, `prod4`, `prod5`, `prod6`, `prod8`, `prod11`, `prod12`, `prod15`, `prod16`, `prod17`, `prod18`, `prod19`, `prod21`, or `prod25`.

See [APIs | Sprinklr Developer Portal](https://dev.sprinklr.com/apis) for the published environment list. Make the base URL a single configuration value rather than hard-coding the host.

> **Environment-scoped everything.** API keys and access tokens are scoped to a single environment — a key generated for one returns `401` against another even when the request is otherwise perfect. The same is true of your data: **`macroIds` and `entityKeys` are environment-specific identifiers.** A macro ID copied from a staging workspace will not resolve in production. This is the most common cause of a `404` on an otherwise correct call.


## Authentication

All calls are authenticated with OAuth 2.0. See [API Overview](https://dev.sprinklr.com/api-overview) for portal registration, API key and secret generation, and the Authorize flow.

### Required headers

| Header | Value | Purpose |
|  --- | --- | --- |
| `Authorization` | `Bearer {{accessToken}}` | Credential used by the API to authenticate a user with the server |
| `Key` | `{{apiKey}}` | API key that authenticates the application with the server. See [API Key and Secret Generation](https://dev.sprinklr.com/api-key-and-secret-generation) |
| `Content-Type` | `application/json` | Determines the type of data present in the request body |
| `Accept` | `application/json` | Determines the acceptable response type from the server |


Both `Authorization` and `Key` are required on every call. Sending only one returns `401`.

> **`Accept: application/json` still matters even though a successful call returns no body.** Error responses *do* return JSON. Keep sending it.


> **The macro runs as the API user.** Macro visibility is governed by workspace and user-level sharing, and the actions a user can take on macros are determined by Macro Permissions. The identity behind your access token must be able to see the macro **and** be permitted to perform every action inside it. A macro that works for an admin in the UI can fail for a service account.


> **One token pair per API key.** Generating a new access token for an API key invalidates the previously issued token and refresh token for that key. Two services sharing one key will knock each other offline. Give each service its own key.


> **Credential hygiene.** Never commit an access token or API key, never paste one into a ticket, and never log the `Authorization` or `Key` header values. Every credential on this page is a placeholder.


## Apply macros

```
POST https://api3.sprinklr.com/{env}/api/v3/macro/apply
```

Applies one or more saved macros to one or more entities of a single asset class.

## Request body

| Field | Type | Required | Description |
|  --- | --- | --- | --- |
| `assetClass` | String | **Yes** | The asset type on which the macro needs to be applied. For example, `UNIVERSAL_CASE` for the case asset type |
| `entityKeys` | Array of strings | **Yes** | Unique identifiers for the entities on which the macro needs to be applied |
| `macroIds` | Array of strings | **Yes** | Unique identifiers for the macros to be applied |


The request is **plural in both dimensions** — N entities × M macros in a single call.

### `assetClass` values

| Value | Entity |
|  --- | --- |
| `UNIVERSAL_CASE` | Case |
| `MESSAGE` | Inbound message |
| `OUTBOUND_MESSAGE` | Outbound message |
| `USER_GENERATED_CONTENT` | UGC asset |
| `SPR_TASK` | Task |
| `PROFILE` | Profile |
| `CAMPAIGN` | Campaign |
| `SUB_CAMPAIGN` | Sub-campaign |
| `MEDIA_ASSET` | Media / SAM asset |
| `ACCOUNT` | Social account |


These values are **case-sensitive**. Define them as a constant set in your own code.

**One `assetClass` per call.** The field is singular, so a batch spanning entity types is not possible — split it into one call per asset class.

### Identifier formats

`entityKeys` and `macroIds` are not the same kind of value:

- `entityKeys` — the format depends on the asset class. For a case this is a case number, a short numeric string such as `"1724559"`.
- `macroIds` — a 24-character hexadecimal identifier such as `"667bf9b8b9d50132d01cfd5d"`.


Match the identifier form to the asset class you are targeting.

### Example request

```bash
curl -X POST \
  'https://api3.sprinklr.com/{env}/api/v3/macro/apply' \
  -H 'Authorization: Bearer {{accessToken}}' \
  -H 'Key: {{apiKey}}' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -d '{
    "assetClass": "UNIVERSAL_CASE",
    "entityKeys": [
      "1724559"
    ],
    "macroIds": [
      "667bf9b8b9d50132d01cfd5d"
    ]
  }'
```

## Response format

A successful call returns:

```
204 No Content
```

**There is no response body.** Write your client so that it never requires a parseable body on success:

```python
resp = requests.post(url, headers=headers, json=body)

if resp.status_code in (200, 204):
    # Success. Do not assume a body exists.
    pass
else:
    errors = resp.json().get("errors", [])   # error responses DO return JSON
```

Accept both `200` and `204` as success. A client that unconditionally deserializes the response body will throw on an empty one.

> **A successful call confirms only that the request was accepted.** The response carries no result object, no per-entity status, and no job ID to poll — so it does not tell you which entities were affected or which macros ran. **To verify an effect, re-fetch the affected entities.** Build that into anything consequential.


Because both `entityKeys` and `macroIds` are arrays, design your calls so that a failure is attributable: use **one `assetClass`, small `entityKeys` batches, and one `macroId` per call** when ordering or outcome tracking matters. This costs more requests but makes failures traceable.

### The error object

Error responses return a JSON body. Each entry in `errors` has this shape:

| Field | Type | Description |
|  --- | --- | --- |
| `id` | String | Error identifier |
| `code` | Integer | Numeric error code |
| `message` | String | Error key, for example `account.not.found` |


Branch on `code` or `message`, not on human-readable text.

## Status codes

| HTTP code | Scenario |
|  --- | --- |
| `204 No Content` | Macro applied. No response body |
| `400 Bad Request` | Missing a required field, unrecognised `assetClass`, malformed JSON, or an `assetClass`/`entityKeys` format mismatch |
| `401 Unauthorized` | Invalid or missing `Authorization` token or `Key` header, or credentials from a different environment |
| `403 Forbidden` | The API user lacks Macro Permissions, cannot see the macro under its visibility rules, or is not permitted to perform an action inside it |
| `404 Not Found` | Unknown `macroId` or `entityKey` — commonly an identifier copied from a different environment or workspace |


### Troubleshooting

| Symptom | Likely cause | Fix |
|  --- | --- | --- |
| Client throws parsing the success response | Success is `204` with an empty body | Accept `200` and `204`; never require a body |
| `404` on every call | Wrong path | The path is `/api/v3/macro/apply` |
| `404` on a call that works elsewhere | `macroId` or `entityKey` from a different environment or workspace | Identifiers are environment- and workspace-scoped |
| `400` on `assetClass` | Value not one of the ten supported, or wrong case | Use one of the listed values exactly |
| `400` mentioning entity keys | `entityKeys` format varies by `assetClass` | Match the identifier form to the asset class |
| `403` though the macro works in the UI | The macro is visible to your admin but not to the API user, or the user lacks permission for an action inside it | Check Macro Permissions and workspace/user visibility |
| `204` returned but nothing changed | The macro contains **Manual Actions** requiring inputs this endpoint cannot supply | Review the macro's configuration with your admin |
| Cannot tell which entities were affected | The success response is empty by design | Re-fetch the entities to verify |
| Some entities updated, others not | Send smaller batches | Batch size determines how attributable a failure is |
| `401` with all headers present | Credentials belong to a different environment | Regenerate for the target environment |
| `401` after previously working | Token expired (30-day default), or a second token was issued for the same key | Refresh; one key per service |
| Behaviour changed without a deploy | An admin edited the macro in the UI | Macro definitions live outside your code |


## Migrating from V2

**Change one character in the path:**

```diff
- POST https://api3.sprinklr.com/{env}/api/v2/macro/apply
+ POST https://api3.sprinklr.com/{env}/api/v3/macro/apply
```

That is the whole endpoint change. Field by field:

| Element | V2 | V3 | Changed? |
|  --- | --- | --- | --- |
| Path after version | `/macro/apply` | `/macro/apply` | No |
| `assetClass` | Required, String, 10 supported values | Identical | No |
| `entityKeys` | Required, array of strings | Identical | No |
| `macroIds` | Required, array of strings | Identical | No |
| Headers | `Authorization`, `Key`, `Content-Type`, `Accept` | Identical | No |
| Success response | `204 No Content` | `204 No Content` | No |


### Migration checklist

1. **Change `v2` to `v3`** in the path. Keep `/macro/apply`.
2. **Change nothing in the request body.** All three fields are unchanged.
3. **Make your response handler accept `200` and `204`** and require no body.
4. **Keep parsing `errors` from the JSON body** on `4xx` responses.
5. **Re-verify `macroIds` and `entityKeys` for the target environment** — identifiers do not travel between environments or workspaces.
6. **Confirm the API user's Macro Permissions and visibility** in the target environment.
7. **Regression-test one macro end to end** by re-fetching the affected entity, since the API returns no confirmation.


## Common tasks

### Close out resolved cases from an external system

When your ticketing system resolves a case, apply a "Close and tag as resolved" macro rather than issuing separate status, tag, and assignment updates:

```json
{
  "assetClass": "UNIVERSAL_CASE",
  "entityKeys": ["1724559"],
  "macroIds": ["667bf9b8b9d50132d01cfd5d"]
}
```

The advantage over calling individual update endpoints is that the action set stays under admin control — if the close-out process changes, the admin edits the macro and your integration needs no deploy.

### Bulk-tag a campaign's assets

One call can carry many entity keys:

```json
{
  "assetClass": "MEDIA_ASSET",
  "entityKeys": ["<id1>", "<id2>", "<id3>"],
  "macroIds": ["<taggingMacroId>"]
}
```

Keep batches small enough that you can attribute a failure, and re-fetch to verify.

### Chain multiple macros

`macroIds` is a list, so several macros can run against the same entities in one call:

```json
{
  "assetClass": "UNIVERSAL_CASE",
  "entityKeys": ["1724559"],
  "macroIds": ["<macroA>", "<macroB>"]
}
```

If two macros write the same field, issue one call per macro so that the order of application is under your control.

### Escalate on an external signal

Configure a macro that sets *Status → Escalated* with *Escalation Reason → "More information needed"*, then fire it from your monitoring system when an SLA threshold is crossed. One API call replaces a multi-field update and keeps the escalation policy in the admin's hands.

## Best practices

**Treat macro IDs as configuration, not constants.** Store them per environment, name them meaningfully in your config, and document which macro each ID refers to. A deleted macro fails at runtime with a `404` and no other warning.

**Verify, don't assume.** The empty success response means the only way to confirm an effect is to re-read the entity.

**Pin down the macro's contents with your admin.** Ask specifically whether it contains Manual Actions or has "Ask user for confirmation" enabled — both are designed for an interactive flow rather than a headless call.

**Match `entityKeys` format to `assetClass`.** Case numbers are short numeric strings; other asset classes use 24-character hexadecimal identifiers.

**One `assetClass` per call.** The field is singular, so split batches that span entity types.

**Do not retry blindly.** There is no idempotency key and no result body, so a retry after a timeout may apply the macro twice. If the macro's actions are not naturally idempotent — appending a tag, incrementing a counter, sending a message — a duplicate application has real effects. Prefer re-fetching the entity to determine whether the first call landed.

**Keep batches small.** Small batches make partial failures attributable and keep you clear of rate limiting.

## Related

- [Apply Macro (V2)](https://dev.sprinklr.com/apply-macro)
- [API Overview](https://dev.sprinklr.com/api-overview)