What?
Summary: this post is to show how you can use SharePoint Designer (2013) to create an item in another list in another site (collection).
If you have ever tried to support a business process within SharePoint with one of the default workflow functionalities, you probably came to the conclusion that you would need to build everything in the same site as there are no ready-to-use actions in a SharePoint Designer Workflow to create a list item in another site or another site collection. I would like to show how you can support the business better by creating items from one site to another site by using the default SharePoint Designer 2013 Workflow actions.
Why?
In some business processes that you want to support with SharePoint, it may occur that there are existing SharePoint Sites where permissions are already exactly configured as desired by business owners and where (even more important) these business owners are already managing access to their sites themselves (preventing those frequent requests to a support department to provide access to certain persons). Would it not be great to make use of these existing sites instead of creating separate sites where access needs to managed separately, just to support specific business processes??
In my case I not only wanted to prevent an extra site to be created, but I wanted to create an environment where one department site would have a ticketing system (SharePoint List) where in the future other multiple departments would also be able to have tickets created from their sites.
(yes… I made this drawing in OneNote off course!)
How?
First let me clarify that SharePoint Designer 2013 is needed and the SharePoint environment will need to have the 2013 Workflow engine working as this will make the Call HTTP Web Service action available in your workflow. This setup should work in SharePoint Online (Office365 – even though PowerApps and Flow will probably make this easier in the nearby future) as well as a SharePoint 2013 and higher On Prem environment. I recommend to get this working in the same site first and then from one site to another, to make troubleshooting easier when the call is not working.
My journey started with a blog post: Using SharePoint REST services from workflow with POST method showing us how this could be achieved, but a non-technical specialist (like myself) wanted to know more about why certain actions where needed and in my test case some essential steps were missing / not explained enough.
Basically there are 2 steps:
- Make sure your workflow from the source site (where your workflow is published) is able to perform actions on the target site
(in the MSDN post: Create a workflow with elevated permissions by using the SharePoint 2013 Workflow platform it is stated that workflow must be published before granting permissions and the user that grants permissions must have Site Owner permissions, but later on in the same post it is stated that permissions are granted to the Workflow app in general and not just a specific workflow. Individual workflows cannot be access controlled. When you enable app permissions you are enabling for all workflows within the Site Collection so I would not see a need to publish the workflow first)
- Create a workflow in your source site with the desired Call HTTP Web Service action
Let me explain these steps in more detail:
- Make sure your workflow from the source site (where sending / posting workflow is published) will be able to perform actions on the target site
- How this is done is explained in detail with full screenshots by MSDN in the post: Create a workflow with elevated permissions by using the SharePoint 2013 Workflow platform but let me explain the steps with some additional information with regards to different sites:
- In Manage site features of source site enable the feature of “Workflows can use app permissions”
- This will add a record to the Site app permissions which can be found in Site Settings of your source site
Copy the App identifier (ID between last | and @) for next steps (n my example this was 8f20f240-ddde-45dc-a08a-66834769220d) - Repeat step 1 for the target site to enable the same feature here
- Add a record manually to the Site app permissions of the target site by visiting the hidden Grant permission to an app page.
This must be done by browsing to the appinv.aspx page of the site. Example: http://{hostname}/{the Site Collection}/{possible subsites}/_layouts/15/appinv.aspx.
Paste your App identifier of the source site, lookup the rest of the information and use the following XML to the App’s Permission Request XML.<AppPermissionRequests> <AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web" Right="FullControl" /> </AppPermissionRequests>
- Give it a Title that will let you know which “App” this record about granting permissions is about – this will be very useful when you will have multiple source sites creating items in the same target site.
I gave it the name Workflow from Source 1 and the last page before creation will be the confirmation to trust this app:
- IMPORTANT: If you disable the feature on the source/target site the call will not succeed or the configuration may even break with the notification in the workflow of “Retrying last request. Details of last request: HTTP InternalServerError to…” and “Invalid text value”
- How this is done is explained in detail with full screenshots by MSDN in the post: Create a workflow with elevated permissions by using the SharePoint 2013 Workflow platform but let me explain the steps with some additional information with regards to different sites:
- Create a workflow in your source site with the desired Call HTTP Web Service action
- Because the workflow is started when an item in the source site is created, the list of the source site will be the list where the workflow is to be created:
- Let me show you the end result of the workflow first and then explain the steps in detail:
I use as much variables as possible because I always want to create a workflow that is reusable and/or changeable without having to republish the workflow for smaller changes / edit all the actions where the same data is used:- TargetSite00URL is the clean url of the target site
(example = https://tenant.sharepoint.com/SC/RESTcallTarget) - TargetSite01ListName is the display name of the target list
(example = TargetList)
IMPORTANT: because this is the display name, you need to update the workflow if the list name changes - CallDesiredAction is the defining action on what to do and the syntax for this purpose =
SP.Data.[title of target list]ListItem
(example = SP.Data.TargetListListItem and instead of typing the list title, I used the variable above)
IMPORTANT: because this is the internal name, you need to be aware that if you change the title of the target list, this one should not be changed and you cannot use the variable anymore
More info on the possible actions can be found online on sites like this post on MSDN: Get to know the SharePoint 2013 REST serviceGet to know the SharePoint 2013 REST service. - CallURL01start is the string used in the HTTP call and the syntax for this purpose =
[url of target root site][possible target subsites]/_api/web/lists/getbytitle(‘[title of target list]’)/items
(example = https://tenant.sharepoint.com/SC/RESTcallTarget/_api/web/lists/getbytitle(‘TargetList’)/items and instead of typing the URL-path and the list title I used the variables above)
- TargetSite00URL is the clean url of the target site
- There are two parts:
- Building the required dictionaries for the (REST) web service call with the Build Dictionary action
- Dictionaries are a new type of variable that supports key-value pairs and in our web service call we need them for:
- header of the request that consists of two keys that will both have the same value:
application/json; odata=verbose
- metadata that determines the type of call
As you can see I have created a variable to determine this value at the start of the workflow. I prefer this because a part of this value is the title of the list and if you want the workflow to be reusable, the title of the target list should be dynamic as explained above. - parameters that consists of a combination of the previous dictionary and all fields that you want to be completed with data
Note that this Dictionary has a key __metadata (2 x _) that has the value of the (previous) Dictionary metadata and all other key-value pairs are the fields of the target list that you want to have data. IMPORTANT: as you can see in my example where my last field was an existing site column to be completed with data from the current item ==> the key needs to be the internal Database name(KpiDescription) and not the Display name(Description).
- header of the request that consists of two keys that will both have the same value:
- Dictionaries are a new type of variable that supports key-value pairs and in our web service call we need them for:
- Call the web service
- In the previously shared post: Create a workflow with elevated permissions by using the SharePoint 2013 Workflow platform more information is given on having this action wrapped in an App step within the workflow. I guess this is best practice as there is a risk that the workflow initiator may not have permissions on the target list, causing the request to be unsuccessful… if you are sure the workflow initiator has permissions on the target site I would recommend not to use the App step so you can see who created the item in the target site.
IMPORTANT: the App step is only available in workflows of sites where you have enabled the feature of “Workflows can use app permissions” as explained in the very first step of this guide. - The Call HTTP Web Service action in the workflow of the source site is best to be edited using the properties of the action (right-click the action in SharePoint Designer en select Properties) because a lot of settings are correct by default:
- The RequestType is HTTP POST (also more info on these types can be found online on multiple sites like the post on MSDN: Working with lists and list items with REST)
- The RequestHeaders is the variable of the dictionary: header
- The RequestContent is the variable of the dictionary: parameters
- The ResponseContent and ResponseStatusCode are variables not needed for input so I created these from this step (but not used anywhere else as input in the workflow so for me they are not relevant)
- In the previously shared post: Create a workflow with elevated permissions by using the SharePoint 2013 Workflow platform more information is given on having this action wrapped in an App step within the workflow. I guess this is best practice as there is a risk that the workflow initiator may not have permissions on the target list, causing the request to be unsuccessful… if you are sure the workflow initiator has permissions on the target site I would recommend not to use the App step so you can see who created the item in the target site.
- Building the required dictionaries for the (REST) web service call with the Build Dictionary action
So now you should be able to create items in other lists and if you do more research on the type of calls that can be done, the possibilities will amaze you!
Hi, Were did ‘Response’ and ‘ResponseCode’ com from?
Hi Dan! Sorry for the reply 🙂
If you are referring to the Response and ResponseCode in the screenshot of the Call HTTP Web Service action, these are variables that you can manually add or are even added by default with this action. From my point of view these variables have no further added value in my explanation to get an item created.
I have not explained this in more detail because I also do not know exactly what they do… my guess is that these variables are similar to the ListItemID variable (like create) that gets automatically created when you create a list item, so you can use responses in this same workflow and maybe even have professional error handling.
Have you tried my steps and noticed something went wrong with regards to these variables?
Thanks, I feel like this is much better explained than the original “Using SharePoint REST services from workflow with POST method” post. I feel like there are a few steps still unclear/unfinished. eg:
– What are the responseContent and responseCode in the HTTP properties?
– You should show the start of your workflow where you’re creating the extra variables. eg CallDesiredAction otherwise I’m stumbling over them later and having to go back and add them.
Also feel the parameters dictionary is still a bit confusing, adding the fields. I assume the Name has to equal the field name at the target destination?
I’m concerned when it comes to lookup fields in the target list. I’ll start playing around and see what i can manage.
Thanks again for the post, got me a lot further than the original.
Also. When the workflow completes with no errors. however there is no new list item in the subsite list. What am I doing wrong?
Thanks so much for replying Django John! Wish I had of ticked to be notified haha, sorry for delay….
The target list is just called “Projects”, I checked it’s the internal list name as well so there’s no “%5” = “_” confusion etc.
My situation: Using Office 365 SP Online. I have a ‘project code’ list on my top level homesite, with a site column, so I can have the project codes across /delivery and /admin subsites. I would like users to click “new project” and create a code on the top level site, but then using this workflow it’ll create a new ‘project’ item on the “/delivery” subsite “projects” list. So they can then add project tasks and more detailed information on our developed project management system in /delivery.
I’ve created this workflow on the top level Project code list, and the workflow looks exactly like your screenshot, and the HTTP web service URL is:
https://[mytenant].sharepoint.com/delivery/_api/web/lists/getbytitle(‘Projects’)/items
Although ideally I’d like this workflow to input the project code (by looking up the site column), project title, customer (another site column lookup) etc, at the moment my parameters is just Title = “Current item: Project title” Single line of text string to single line of text. I’ll battle the lookups once I’ve got an item to appear in the Projects list at all.
I hope I’ve explained the situation enough, and apologies for any confusion.
thanks so much in advance for any guidance as to why nothing is appearing in my Projects list on the /delivery subsite.
-Kim
Hi Kim,
Sorry for the late reply but I really wanted to take my time to “trace back” my steps in a fresh (SharePoint Online) environment and this took some preparation / time.
I added a lot of extra screenshots and information because (like you probably have discovered) the internal name and display name of lists as well as columns may be causing your issue. Could you please check if this helps?
1-Looking at your URL https://[mytenant].sharepoint.com/delivery/_api/web/lists/getbytitle(‘Projects’)/items and the fact that delivery is a subsite of your project root site ==> should the subsite not be in the URL like ==> https://[mytenant].sharepoint.com/sites/{name of project root site}/delivery/_api/web/lists/getbytitle(‘Projects’)/items?
2-Does the workflow give an error or does it state that it completed successfully?
3-Maybe you can add some logging information to see where the workflow picks up wich information (in my example I log the CallDesiredAction and the CallURL01start variables to see if the info is picked up correctly)
4-Notice the double _ in the __metadata dictionary of variables
5-Doublecheck the correct types of variables in all the dictionaries and the exact spelling
Hi Kim,
First if your worflow completes without error check (with a log) the ResponseStatusCode of your HTTP call.
It must be a BadRequest (i fight over it for 1week grrrr) the you have to check the value of your RequestContent in order to fight where it comes from.
About Lookup fields check the real field name of your lookup.
For example i have to copy a field containing users wich i call Commercial, i try a get Call https://sitename.sharepoint.com/yoursubsite/_api/web/lists/getbytitle('listname‘)/items and i saw that my Commercial was in fact named CommercialId and the walue was an integer.
So in your Dictionnary the name of your field has to be XXXId the Type : Integer (depending of your language).
And it works for me 🙂
Cheers
How to get internal database names for list columns?
Hello Ballu, the way that I (also in Modern Interface) still verify the internal database name is to open the List Settings and hover over the column name so I can see the URL.
Example = https://[tenant].sharepoint.com/SC/RESTcallTarget/_layouts/15/FldEditEx.aspx?List=%5BListID%5D&Field=Author
The display name = Created by
The internal name = Author
Hi,
I’m facing the same problem as Kim the worklow complete with no errors an i have a bad request in response Header, any idea ?
Sorry it’s the response Statut code that contains a Badrequest message
Thank you so much David for taking the time to follow up on your issue and maybe even answer one of the issues that Kim may have 🙂
things are clear…everything works now… i re-create step by step my workflow
With no experience in this sort of thing, only minor OOTB SPD workflows for notifications, I worked through the instructions as best I could. Upon completion, I did not see a newly created item added to my other list, as I would expect. I checked the new log that the workflow created and saw that it was in Suspended status with the following message:
RequestorId: 1e5e2b48-08a3-93ff-0000-000000000000. Details: An unhandled exception occurred during the execution of the workflow instance. Exception details: System.UriFormatException: Invalid URI: The URI scheme is not valid. at System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind) at Microsoft.Activities.Messaging.SendHttpRequest.SendRequest(NativeActivityContext context) at System.Activities.NativeActivity.InternalExecute(ActivityInstance instance, ActivityExecutor executor, BookmarkManager bookmarkManager) at System.Activities.Runtime.ActivityExecutor.ExecuteActivityWorkItem.ExecuteBody(ActivityExecutor executor, BookmarkManager bookmarkManager, Location resultLocation) Exception from activity SendHttpRequest HttpPost Switch Sequence Microsoft.SharePoint.WorkflowServices.Activities.CallHTTPWebService App Step Stage 1 Sequence Flowchart SourceList.WorkflowXaml_68b499ca_1a8a_4e9d_acf8_a70dae0e218f
I hope this is enough information to determine what I may have done wrong.
Can you identify the problem or provide some direction to resolve this?
Hi Tim, it could be the url or one of the variables defined in the workflow. Please double check on url with correct site path, variables with correct list names and columns with correct (internal) database name.
Thanks for sharing this. I tried but it did not work. I didn’t get any bad request. My workflow history logged the two items as indicated on the workflow. Any idea? I verified that the target site now has the workflow ID of my source site. But after running the workflow, it didn’t create a new item in my target list.
Hi Sharon, please check one of the common mistakes above? Maybe post the info you have like which variables, actions and loggings?
Hi – Have you any ideas why I would be getting Forbidden as a response back from a HTTP Post request? I have created the same request on another site collection which works perfectly but I’ve recreated it on a similar site and it just gives back Forbidden Access Denied. I’ve elevated workflow app permissions etc.
If the same workflow is working from Site A to Site B but not from Site A to Site C, I would assume that there is no bad request.
The App Step is used in the workflow?
Did you activate the needed site features on all sites and also use the correct App Id in the Site App Permissions of the second target site?
I am trying to follow your example but am getting the following error:
Suspend this workflow
Activity in progress
Retrying last request. Next attempt scheduled in less than one minute. Details of last request: HTTP InternalServerError to https://mysite.sharepoint.com/sites/6269/_api/web/lists(guid'36c6c56a-020d-4d7f-8d31-0dc0a616e4be‘)/Items Correlation Id: ef92f1d4-d9d9-fcd9-a2d1-86bf129306ea Instance Id: 7e3105e9-b161-4b0e-a162-2f960c8fbfca
Invalid text value.
A text field contains invalid data. Please check the value and try again.
Retry now
Any Suggestions?
Django nice article… I followed your example carefully but am getting this error “An entry without a type name was found, but no expected type was specified” and having issues getting it resolved… I have Parent site with list (2 fields – Title & Group), subsite with same list “ProjStatus” (2 fields Title & Group) any ideas?
I have another workflow on the parent site that creates subsites from a request list so Elevate Permissions is working. Below are the variables and response codes form the Work flow for test:
— requestHeaders: {“Accept”:”application\/json;odata=verbose”,”Content-Type”:”application\/json;odata=verbose”}
— request: {“parameters”:{“__metadata”:{“type”:”SP.DATA.ProjStatusListItem”},”Title”:”Sample”,”Group”:”LAN”,”UseUniquePermissions”:”false”},”LoginName”:”i:0#.f|membership|a27mmm@mysite.com”}
— response: {“error”:{“code”:”-1, Microsoft.SharePoint.Client.InvalidClientQueryException”,”message”:{“lang”:”en-US”,”value”:”An entry without a type name was found, but no expected type was specified. To allow entries without type information, the expected type must also be specified when the model is specified.”}}}
— _ResponseCode: BadRequest
Variables:
— CallURL01start: https://mysite.sharepoint.com/sites/6269/SPTESTSITE/_api/web/lists/getbytitle('ProjStatus‘)/items
— metadata: {“type”:”SP.DATA.ProjStatusListItem”}
— parameters: {“parameters”:{“__metadata”:{“type”:”SP.DATA.ProjStatusListItem”},”Title”:”Sample”,”Group”:”LAN”,”UseUniquePermissions”:”false”},”LoginName”:”i:0#.f|membership|a27mmm@mysite.com”}
Hi Tony,
Did you see David his comment above? Maybe the type of field is causing this error.
Did you select the right type of value (String, Integer etc) for both fields?
Maybe first try a simple test with just the Title field to see if that works?
Hii,
Django nice article….
is it work for Library or not, i want to copy document from one site collection to another site collection.
is very
The same functionalities should work but I remember the REST Call needs different data. Please search online for examples.
Hi Django,
I have followed, everything in this post, my workflow kicks in. But Http service is not creating list item in other subsite. Any help?
Hi Manoj, please see comments above. There are many points of error posible…
Hi,
for all of you having “Bad Request” error – check CallDesiredAction variable. In my case it was one missing dot… Took me a while to find it.
I really need some help here. I executed the steps described above very carefully, but somehow after not able to get past the BadRequest response code. My logging show following values,
CallURL01Start =
https://scopesptest.sharepoint.com/teams/Collection_02_Team_Site/_api/web/lists/getbytitle('Target_List‘)/items
CallDesiredAction = SP.DATA.Target_ListListItem
header = {“Accept”:”application\/json; odata=verbose”,”Content-Type”:”application\/json; odata=verbose”}
metadata = {“type”:”SP.DATA.Target_ListListItem”}
parameters = {“__metadata”:{“type”:”SP.DATA.Target_ListListItem”},”Title”:”Test 0006″}
responseCode = BadRequest
In my header variable above, why does it convert my value to have both forward and backward slashes (\ /), even though I gave only one slash in my dictionary variable value
application\/json; odata=verbose
Also when i visit the link above (inCallURL01Start), then what shouuld it generally show.
Thank-you so much for any pointers.