Workflow (HTTP Request - Created a Cert Campmagin)

Hello everyone,

I’m trying to create a certification campaign using the HTTP Request card in a SailPoint Workflow, but I keep running into an 400 Bad Request error. I’m very new to SailPoint Workflows, so I apologise if this is something obvious.

Here’s what I’m doing:

  • I’m calling the API endpoint:

    https://<tenant>.api.identitynow.com/v2024/campaigns
    
    
  • Method: POST

  • Request Content Type: JSON

  • Authentication: OAuth 2.0

  • This is the exact JSON body I’m using (copied directly into the card):

{
  "name": "Role Review for {{$.getIdentity.displayName}}",
  "description": "Manager reviews only roles for {{$.getIdentity.displayName}}",
  "type": "SEARCH",
  "deadline": "{{@formatDate(@addDays(@now(),14), \"yyyy-MM-dd'T'HH:mm:ss'Z'\")}}",
  "emailNotificationEnabled": true,
  "searchCampaignInfo": {
    "type": "ACCESS",
    "query": "type:role",
    "identityIds": ["{{$.trigger.identity.id}}"],
    "reviewer": {
      "type": "IDENTITY",
      "id": "{{$.getIdentity.managerRef.id}}"
    }
  }
}

The workflow is triggered whenever a user’s managerId changes in SailPoint, and the goal is to automatically create a 14-day campaign for the new manager to review that user’s roles.

However, no matter what I try, I always get this error:

400 - Bad Request - The request could not be parsed.

If I replace the variables with real (static) values, the campaign is created successfully. So I’m certain the issue is related to how I’m referencing the variables or formatting the JSON in the workflow.

Has anyone successfully created a campaign using dynamic variables inside a workflow HTTP Request?

Hi @luissebastiao Can you post your whole workflow JSON file here by masking any sensitive info?

Hey,

Thanks for the quick response. This is my completed Workflow so far. Still need to add the Slack HTTP Request part, but for now, I am trying to solve the issue with creating the campaign.

{
	"name": "Manager Change Approvals",
	"description": "",
	"modified": "2025-10-16T12:56:51.181317376Z",
	"modifiedBy": {
		"type": "IDENTITY",
		"id": "XXXXXXXXXXXXX",
		"name": "XXXXXXXXXXXX"
	},
	"definition": {
		"start": "Get Identity",
		"steps": {
			"Compare Numbers": {
				"actionId": "sp:compare-numbers",
				"choiceList": [
					{
						"comparator": "NumericGreaterThanEquals",
						"nextStep": "Send Email",
						"variableA.$": "$.getListOfIdentities.identities.length()",
						"variableB": 1
					}
				],
				"defaultStep": "HTTP Request 3",
				"displayName": "Check if Manager is on the list",
				"type": "choice"
			},
			"Compare Numbers 1": {
				"actionId": "sp:compare-numbers",
				"choiceList": [
					{
						"comparator": "NumericGreaterThanEquals",
						"nextStep": "Send Email",
						"variableA.$": "$.getListOfIdentities.identities.length()",
						"variableB": 1
					}
				],
				"defaultStep": "HTTP Request 4",
				"displayName": "Check if Manager is on the list",
				"type": "choice"
			},
			"Compare Timestamps": {
				"actionId": "sp:compare-timestamps",
				"choiceList": [
					{
						"comparator": "TimestampEquals",
						"nextStep": "Define Variable",
						"variableA.$": "$.getIdentity.attributes.lastJobChange",
						"variableB": "{{ now() }}"
					}
				],
				"defaultStep": "Compare Timestamps 1",
				"displayName": "Is date today?",
				"type": "choice"
			},
			"Compare Timestamps 1": {
				"actionId": "sp:compare-timestamps",
				"choiceList": [
					{
						"comparator": "TimestampEquals",
						"nextStep": "Define Variable",
						"variableA.$": "$.getIdentity.attributes.lastJobChange",
						"variableB": "{{ addDays(now(), 1) }}"
					}
				],
				"defaultStep": "Compare Timestamps 2",
				"displayName": "Is date tomorrow? ",
				"type": "choice"
			},
			"Compare Timestamps 2": {
				"actionId": "sp:compare-timestamps",
				"choiceList": [
					{
						"comparator": "TimestampEquals",
						"nextStep": "Define Variable",
						"variableA.$": "$.getIdentity.attributes.lastJobChange",
						"variableB": "{{ addDays(now(), -1) }}"
					}
				],
				"defaultStep": "End Step - Success 2",
				"displayName": "Is on Date Yesterday?",
				"type": "choice"
			},
			"Define Variable": {
				"actionId": "sp:define-variable",
				"attributes": {
					"id": "sp:define-variable",
					"variables": [
						{
							"description": "",
							"name": "reviewerId",
							"transforms": [],
							"variableA.$": "$.getIdentity.managerRef.id"
						},
						{
							"description": "",
							"name": "queryStr",
							"transforms": [],
							"variableA": "attributes.email:\"{{$.getIdentity.attributes.managerId}}\" AND attributes.cloudLifecycleState:Active AND NOT manager.email:\"{{$.getIdentity.attributes.managerId}}\""
						},
						{
							"description": "",
							"name": "userId",
							"transforms": [],
							"variableA.$": "$.trigger.identity.id"
						},
						{
							"description": "",
							"name": "displayName",
							"transforms": [],
							"variableA.$": "$.getIdentity.displayName"
						}
					]
				},
				"displayName": "Variables",
				"nextStep": "Get List of Identities",
				"type": "Mutation"
			},
			"End Step - Failure": {
				"actionId": "sp:operator-failure",
				"displayName": "",
				"failureName": "User not created",
				"type": "failure"
			},
			"End Step - Success 1": {
				"actionId": "sp:operator-success",
				"description": "Workflow stopped: The identity's new managerId attribute is null.",
				"displayName": "End Step - ManagerID is Null",
				"type": "success"
			},
			"End Step - Success 2": {
				"actionId": "sp:operator-success",
				"displayName": "End Step - No Valid Date",
				"type": "success"
			},
			"End Step - Success 3": {
				"actionId": "sp:operator-success",
				"description": "All Cert Send to the Manager",
				"displayName": "End Step - Completed",
				"type": "success"
			},
			"Get Identity": {
				"actionId": "sp:get-identity",
				"attributes": {
					"id.$": "$.trigger.identity.id"
				},
				"displayName": "",
				"nextStep": "Verify Data Type",
				"type": "action",
				"versionNumber": 2
			},
			"Get List of Identities": {
				"actionId": "sp:get-identities",
				"attributes": {
					"inputQuery.$": "$.defineVariable.queryStr",
					"searchBy": "searchQuery"
				},
				"displayName": "Check if Manager is on Sailpoint",
				"nextStep": "Compare Numbers",
				"type": "action",
				"versionNumber": 2
			},
			"Get List of Identities 1": {
				"actionId": "sp:get-identities",
				"attributes": {
					"inputQuery.$": "$.defineVariable.queryStr",
					"searchBy": "searchQuery"
				},
				"displayName": "Check if Manager is on Sailpoint",
				"nextStep": "Compare Numbers 1",
				"type": "action",
				"versionNumber": 2
			},
			"HTTP Request": {
				"actionId": "sp:http",
				"attributes": {
					"authenticationType": "OAuth",
					"jsonRequestBody": {
						"deadline": "{{@formatDate(@addDays(@now(),14), \"yyyy-MM-dd'T'HH:mm:ss'Z'\")}}",
						"description": "Manager reviews only roles for {{$.getIdentity.displayName}}",
						"emailNotificationEnabled": true,
						"name": "Role Review for {{$.getIdentity.displayName}}",
						"searchCampaignInfo": {
							"identityIds": [
								"{{$.trigger.identity.id}}"
							],
							"query": "type:role",
							"reviewer": {
								"id": "{{$.getIdentity.managerRef.id}}",
								"type": "IDENTITY"
							},
							"type": "ACCESS"
						},
						"type": "SEARCH"
					},
					"method": "post",
					"oAuthClientId": "XXXXXXXXXXXXX",
					"oAuthClientSecret": "XXXXXXXXXXXXXXXXXXXX",
					"oAuthScope": null,
					"oAuthTokenUrl": "https://XXXXXXXXXXXXXXXX.api.identitynow.com/oauth/token",
					"requestContentType": "json",
					"url": "https://XXXXXXXXXXXXXXX.api.identitynow.com/v2024/campaigns"
				},
				"displayName": "Created Campaign ",
				"nextStep": "End Step - Success 3",
				"type": "action",
				"versionNumber": 2
			},
			"HTTP Request 3": {
				"actionId": "sp:http",
				"attributes": {
					"authenticationType": "OAuth",
					"method": "post",
					"oAuthClientId": "XXXXXXXXXXXXXXXXXX",
					"oAuthClientSecret": "XXXXXXXXXXXXX",
					"oAuthCredentialLocation": "oAuthInHeader",
					"oAuthTokenUrl": "https://XXXXXXXXXXXXX.api.identitynow.com/oauth/token",
					"url": "https://XXXXXXXXXXXX.api.identitynow.com/v2024/sources/XXXXXXXXXXXXXXXXXX/load-accounts"
				},
				"displayName": "Run Account Aggregation",
				"nextStep": "Wait 1",
				"type": "action",
				"versionNumber": 2
			},
			"HTTP Request 4": {
				"actionId": "sp:http",
				"attributes": {},
				"displayName": "Send Slack Message (Error)",
				"nextStep": "End Step - Failure",
				"type": "action",
				"versionNumber": 2
			},
			"Send Email": {
				"actionId": "sp:send-email",
				"attributes": {
					"body": "<p>Certification Camp Testing</p>",
					"context": {},
					"from": null,
					"recipientEmailList.$": "$.getIdentity.attributes.managerId",
					"subject": "Certification Camp"
				},
				"displayName": "Send Email (Campaign Start)",
				"nextStep": "HTTP Request",
				"type": "action",
				"versionNumber": 2
			},
			"Verify Data Type": {
				"actionId": "sp:compare-unary",
				"choiceList": [
					{
						"comparator": "IsNull",
						"nextStep": "End Step - Success 1",
						"variableA.$": "$.getIdentity.attributes.managerId"
					}
				],
				"defaultStep": "Verify Data Type 1",
				"description": "Check if the new managerId attribute value is null.",
				"displayName": "Is ManagerID Null?",
				"type": "choice"
			},
			"Verify Data Type 1": {
				"actionId": "sp:compare-unary",
				"choiceList": [
					{
						"comparator": "IsNull",
						"nextStep": "Define Variable",
						"variableA.$": "$.getIdentity.attributes.lastJobChange"
					}
				],
				"defaultStep": "Compare Timestamps",
				"displayName": "Is LastJobChangeDate Null?",
				"type": "choice"
			},
			"Wait 1": {
				"actionId": "sp:sleep",
				"attributes": {
					"duration": "1m",
					"type": "waitFor"
				},
				"displayName": "",
				"nextStep": "Get List of Identities 1",
				"type": "action",
				"versionNumber": 1
			}
		}
	},
	"creator": {
		"type": "IDENTITY",
		"id": "XXXXXXXXXXXXXX",
		"name": "XXXXXXXXXXXXXXX"
	},
	"trigger": {
		"type": "EVENT",
		"attributes": {
			"attributeToFilter": "managerId",
			"filter.$": "$.changes[?(@.attribute == \"managerId\")]",
			"id": "idn:identity-attributes-changed"
		}
	}
}


Can you try changing {{$.getIdentity.displayName}} to {{$.getIdentity.attributes.displayName}}

Still not working. I did notice that during the execution Sailpoint is adding suppliedInlineExpression to the HTTP Request, but from what i was reading, that may be the issue.

Just out of curiosity, can you try it without the deadline? I’m wondering if there’s something off about the escaping