After much trial and travail and some crucial help from JasperSoft support, I was able to get my use case to work under JasperReport Server 5.2. I thought I would post the answer here in the hope that it may help someone else. Here's the code to add a content resource (in this case a PDF) to the JasperReport Server repository using the resource REST web service. This code uses the Spring 3.1 RestTemplate: public void process(byte[] reportBytes, String fileNameBase) { // Prepare the ResourceDescriptor XML part String resourceDescriptor = "<resourceDescriptor name="TestReport.pdf" wsType="contentResource" uriString="/reports/samples/TestReport.pdf" isNew="false">" + "n" + " <label><![CDATA[TestReport.pdf]]></label>" + "n" + " <creationDate>1373380817231</creationDate>" + "n" + " <resourceProperty name="PROP_RESOURCE_TYPE">" + "n" + " <value><![CDATA[com.jaspersoft.jasperserver.api.metadata.common.domain.ContentResource]]></value>" + "n" + " </resourceProperty>" + "n" + " <resourceProperty name="PROP_PARENT_FOLDER">" + "n" + " <value><![CDATA[/reports/samples]]></value>" + "n" + " </resourceProperty>" + "n" + " <resourceProperty name="PROP_VERSION">" + "n" + " <value><![CDATA[0]]></value>" + "n" + " </resourceProperty>" + "n" + " <resourceProperty name="PROP_SECURITY_PERMISSION_MASK">" + "n" + " <value><![CDATA[1]]></value>" + "n" + " </resourceProperty>" + "n" + " <resourceProperty name="CONTENT_TYPE">" + "n" + " <value><![CDATA[pdf]]></value>" + "n" + " </resourceProperty>" + "n" + " <resourceProperty name="DATA_ATTACHMENT_ID">" + "n" + " <value><![CDATA[/reports/samples/TestReport.pdf]]></value>" + "n" + " </resourceProperty>" + "n" + " <resourceProperty name="PROP_HAS_DATA">" + "n" + " <value><![CDATA[true]]></value>" + "n" + " </resourceProperty>" + "n" + "</resourceDescriptor>" + "n"; HttpHeaders descriptorHeaders = new HttpHeaders(); descriptorHeaders.setContentType(new MediaType("text", "plain", Charset.forName("UTF-8"))); descriptorHeaders.set("Content-Transfer-Encoding", "8bit"); HttpEntity<String> descriptorEntity = new HttpEntity<String>(resourceDescriptor, descriptorHeaders); // Prepare the contentResource binary part Resource reportResource = new ByteArrayResource(reportBytes) { @Override public String getFilename() throws IllegalStateException { return "TestReport.pdf"; } }; HttpHeaders resourceHeaders = new HttpHeaders(); resourceHeaders.setContentType(new MediaType("application", "octet-stream", Charset.forName("UTF-8"))); resourceHeaders.set("Content-Transfer-Encoding", "binary"); HttpEntity<Resource> resourceEntity = new HttpEntity<Resource>(reportResource, resourceHeaders); // Prepare the multipart form MultiValueMap<String, HttpEntity<?>> form = new LinkedMultiValueMap<String, HttpEntity<?>>(); form.add("ResourceDescriptor", descriptorEntity); form.add("/reports/samples/TestReport.pdf", resourceEntity); HttpHeaders headers = new HttpHeaders(); headers.setContentType(new MediaType("multipart", "form-data")); HttpEntity<MultiValueMap<String, HttpEntity<?>>> request = new HttpEntity<MultiValueMap<String, HttpEntity<?>>>(form, headers); restTemplate.put(getJasperReportsServerUrl() + "/rest/resource/reports/samples/TestReport.pdf", request); }[/code]To add a content resource, the resource REST web service requires that the client send a multi-part form in a PUT request with the HTTP header Content-Type "multipart/form-data". This request must consist of two parts: The first part is the new resource's ResourceDescriptor as an XML string. This part be named "ResourceDescriptor". It must be sent with HTTP headers Content-Type "text/plain; charset=UTF-8" and Content-Transfer-Encoding "8bit". There are requirements for the contents of this resource descriptor, as will be discussed later. The second part is the binary data for the resource. This part must be named as the path and filename of the resource. It must be sent with the HTTP headers Content-type "application/octet-stream; charset=UTF=8", Content-Transfer-Encoding "binary", and Content-Disposition "filename=<filename>.<ext>" where <filename>.<ext> is the filename of the resource. It was failure to supply this last header that caused the 400 - Bad Request status that was the reason for my original post. It is unintuitive why this should cause a failure to unmarshall the ResourceDescriptor from the XML in the first part, but it does. In any case, the ResourceDescriptor must contain the attributes and parameters as given in the example or the request will come to grief. In particular, the path and filename given in the request URL, the name and uriString attributes, the PARENT_FOLDER and DATA_ATTACHMENT_ID properties must all be consistent with each other and with the filename attribute of the Content-Disposition header in the second part. Interestingly, the value of the isNew attribute doesn't seem to have any effect on the request. This is a lot of hoops to jump through, so it's no wonder that so many people have had problems with it.