diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h b/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h
index 66c61f8e6213662a638ac22bb407e4caf1b94c7a..353bce4b01d06c353d7e20da9728844e700aa210 100644
--- a/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h
+++ b/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h
@@ -38,6 +38,7 @@
 #error "Please do not include this file directly, use ipaaca.h instead"
 #endif
 
+// casting operators from Value&
 IPAACA_HEADER_EXPORT template<typename T> T json_value_cast(const rapidjson::Value&);
 IPAACA_HEADER_EXPORT template<typename T> T json_value_cast(const rapidjson::Value* value) { if (!value) return T(); return json_value_cast<T>(*value); }
 IPAACA_HEADER_EXPORT template<> long json_value_cast(const rapidjson::Value&);
@@ -48,6 +49,47 @@ IPAACA_HEADER_EXPORT template<> std::vector<std::string> json_value_cast(const r
 IPAACA_HEADER_EXPORT template<> std::list<std::string> json_value_cast(const rapidjson::Value&);
 IPAACA_HEADER_EXPORT template<> std::map<std::string, std::string> json_value_cast(const rapidjson::Value&);
 
+// helpers to set Value& from various standard types
+IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, T t);
+IPAACA_HEADER_EXPORT template<> void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, long);
+IPAACA_HEADER_EXPORT template<> void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, double);
+IPAACA_HEADER_EXPORT template<> void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, bool);
+IPAACA_HEADER_EXPORT template<> void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, const std::string&);
+
+IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::vector<T>& ts)
+{
+	valueobject.SetArray();
+	for (auto& val: ts) {
+		rapidjson::Value newv;
+		pack_into_json_value<T>(newv, allocator, val);
+		valueobject.PushBack(newv, allocator);
+	}
+}
+IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::list<T>& ts)
+{
+	valueobject.SetArray();
+	for (auto& val: ts) {
+		rapidjson::Value newv;
+		pack_into_json_value<T>(newv, allocator, val);
+		valueobject.PushBack(newv, allocator);
+	}
+}
+IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::map<std::string, T>& ts)
+{
+	valueobject.SetObject();
+	for (auto& val: ts) {
+		rapidjson::Value key;
+		key.SetString(val.first, allocator);
+		rapidjson::Value newv;
+		pack_into_json_value<T>(newv, allocator, val.second);
+		valueobject.AddMember(key, newv, allocator);
+	}
+}
+/*IPAACA_HEADER_EXPORT template<> void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, const std::vector<std::string>&);
+IPAACA_HEADER_EXPORT template<> void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, const std::list<std::string>&);
+IPAACA_HEADER_EXPORT template<> void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, const std::map<std::string, std::string>&);
+*/
+
 // FIXME TODO locking / invalidating proxy on first write of a payload entry
 IPAACA_HEADER_EXPORT class PayloadDocumentEntry//{{{
 {
@@ -62,6 +104,7 @@ IPAACA_HEADER_EXPORT class PayloadDocumentEntry//{{{
 		IPAACA_HEADER_EXPORT std::string to_json_string_representation();
 		static std::shared_ptr<PayloadDocumentEntry> from_json_string_representation(const std::string& input);
 		static std::shared_ptr<PayloadDocumentEntry> create_null();
+		std::shared_ptr<PayloadDocumentEntry> clone();
 	typedef std::shared_ptr<PayloadDocumentEntry> ptr;
 };
 //}}}
@@ -85,8 +128,6 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{
 		rapidjson::Value* json_value;
 	protected:
 		IPAACA_HEADER_EXPORT void connect_to_existing_parents();
-	protected:
-		IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(T t); //specializations below
 	public:
 		// constructor to create a new top-most parent proxy (from a payload key)
 		IPAACA_HEADER_EXPORT PayloadEntryProxy(Payload* payload, const std::string& key);
@@ -101,6 +142,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{
 		IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(const char* value);
 		IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(double value);
 		IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(bool value);
+		
 		IPAACA_HEADER_EXPORT operator std::string();
 		IPAACA_HEADER_EXPORT operator long();
 		IPAACA_HEADER_EXPORT operator double();
@@ -158,14 +200,6 @@ IPAACA_HEADER_EXPORT template<> std::list<std::string> PayloadEntryProxy::get();
 IPAACA_HEADER_EXPORT template<> std::map<std::string, std::string> PayloadEntryProxy::get();
 */
 
-// value converters
-IPAACA_HEADER_EXPORT template<> void PayloadEntryProxy::pack_into_json_value(long);
-IPAACA_HEADER_EXPORT template<> void PayloadEntryProxy::pack_into_json_value(double);
-IPAACA_HEADER_EXPORT template<> void PayloadEntryProxy::pack_into_json_value(bool);
-IPAACA_HEADER_EXPORT template<> void PayloadEntryProxy::pack_into_json_value(const std::string&);
-IPAACA_HEADER_EXPORT template<> void PayloadEntryProxy::pack_into_json_value(const std::vector<std::string>&);
-IPAACA_HEADER_EXPORT template<> void PayloadEntryProxy::pack_into_json_value(const std::list<std::string>&);
-IPAACA_HEADER_EXPORT template<> void PayloadEntryProxy::pack_into_json_value(const std::map<std::string, std::string>&);
 //}}}
 
 /*
diff --git a/ipaacalib/cpp/src/ipaaca-json.cc b/ipaacalib/cpp/src/ipaaca-json.cc
index f7c74deb71b696f8326e5536faef4aa1d9bfc022..d5dd285cc9b9aa6839da7bff1b25907998107adf 100644
--- a/ipaacalib/cpp/src/ipaaca-json.cc
+++ b/ipaacalib/cpp/src/ipaaca-json.cc
@@ -128,6 +128,19 @@ int main(int argc, char** argv) {
 		std::cout << "(n/a)" << std::endl;
 	}
 	
+	//iu->payload()["b"] = "newEntry";
+	
+	//std::vector<long> vs = { 10, 20, 30, 40 };
+	std::map<std::string, double> vs = { {"A", 10}, {"B", 20}, {"C", 30}, {"D", 40} };
+	ipaaca::pack_into_json_value(entry->document, entry->document.GetAllocator(), vs);
+	{
+		StringBuffer buffer;
+		Writer<StringBuffer> writer(buffer);
+		entry->document.Accept(writer);
+		std::string docstring = buffer.GetString();
+		std::cout << "Final document:  " << docstring << std::endl;
+	}
+	
 	// Done
 	return 0;
 
diff --git a/ipaacalib/cpp/src/ipaaca-payload.cc b/ipaacalib/cpp/src/ipaaca-payload.cc
index a50222677955212950048235a98934bf71918cc7..aeb95163905f0525325cc99c5d21cc5bf6d31ade 100644
--- a/ipaacalib/cpp/src/ipaaca-payload.cc
+++ b/ipaacalib/cpp/src/ipaaca-payload.cc
@@ -56,7 +56,7 @@ IPAACA_EXPORT std::ostream& operator<<(std::ostream& os, const Payload& obj)//{{
 //}}}
 
 // json_value_cast//{{{
-IPAACA_HEADER_EXPORT template<> std::string json_value_cast(const rapidjson::Value& v)
+IPAACA_EXPORT template<> std::string json_value_cast(const rapidjson::Value& v)
 {
 	if (v.IsString()) return v.GetString();
 	if (v.IsNull()) return "";
@@ -65,7 +65,7 @@ IPAACA_HEADER_EXPORT template<> std::string json_value_cast(const rapidjson::Val
 	v.Accept(writer);
 	return buffer.GetString();
 }
-IPAACA_HEADER_EXPORT template<> long json_value_cast(const rapidjson::Value& v)
+IPAACA_EXPORT template<> long json_value_cast(const rapidjson::Value& v)
 {
 	if (v.IsString()) return atol(std::string(v.GetString()).c_str());
 	if (v.IsInt()) return v.GetInt();
@@ -81,7 +81,7 @@ IPAACA_HEADER_EXPORT template<> long json_value_cast(const rapidjson::Value& v)
 	v.Accept(writer);
 	return atol(std::string(buffer.GetString()).c_str());
 }
-IPAACA_HEADER_EXPORT template<> double json_value_cast(const rapidjson::Value& v)
+IPAACA_EXPORT template<> double json_value_cast(const rapidjson::Value& v)
 {
 	if (v.IsString()) return atof(std::string(v.GetString()).c_str());
 	if (v.IsDouble()) return v.GetDouble();
@@ -97,7 +97,7 @@ IPAACA_HEADER_EXPORT template<> double json_value_cast(const rapidjson::Value& v
 	v.Accept(writer);
 	return atof(std::string(buffer.GetString()).c_str());
 }
-IPAACA_HEADER_EXPORT template<> bool json_value_cast(const rapidjson::Value& v)
+IPAACA_EXPORT template<> bool json_value_cast(const rapidjson::Value& v)
 {
 	if (v.IsString()) {
 		std::string s = v.GetString();
@@ -126,15 +126,51 @@ IPAACA_HEADER_EXPORT template<> bool json_value_cast(const rapidjson::Value& v)
 			*/
 //}}}
 
+IPAACA_EXPORT template<> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, long newvalue)
+{
+	valueobject.SetInt(newvalue);
+}
+IPAACA_EXPORT template<> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, double newvalue)
+{
+	valueobject.SetDouble(newvalue);
+}
+IPAACA_EXPORT template<> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, bool newvalue)
+{
+	valueobject.SetBool(newvalue);
+}
+IPAACA_EXPORT template<> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::string& newvalue)
+{
+	valueobject.SetString(newvalue.c_str(), allocator);
+}
+/*
+IPAACA_EXPORT template<> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::vector<std::string>& newvalue)
+{
+	valueobject.SetArray();
+	for (auto& str: newvalue) {
+		rapidjson::Value sv;
+		sv.SetString(str, allocator);
+		valueobject.PushBack(sv, allocator);
+	}
+}
+IPAACA_EXPORT template<> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::list<std::string>& newvalue)
+{
+	IPAACA_IMPLEMENT_ME
+}
+IPAACA_EXPORT template<> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::map<std::string, std::string>& newvalue)
+{
+	IPAACA_IMPLEMENT_ME
+}
+*/
+
 // PayloadDocumentEntry//{{{
-IPAACA_HEADER_EXPORT inline std::string PayloadDocumentEntry::to_json_string_representation()
+IPAACA_EXPORT inline std::string PayloadDocumentEntry::to_json_string_representation()
 {
 	rapidjson::StringBuffer buffer;
 	rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
 	document.Accept(writer);
 	return buffer.GetString();
 }
-IPAACA_HEADER_EXPORT PayloadDocumentEntry::ptr PayloadDocumentEntry::from_json_string_representation(const std::string& json_str)
+IPAACA_EXPORT PayloadDocumentEntry::ptr PayloadDocumentEntry::from_json_string_representation(const std::string& json_str)
 {
 	PayloadDocumentEntry::ptr entry = std::make_shared<ipaaca::PayloadDocumentEntry>();
 	if (entry->document.Parse(json_str.c_str()).HasParseError()) {
@@ -143,12 +179,17 @@ IPAACA_HEADER_EXPORT PayloadDocumentEntry::ptr PayloadDocumentEntry::from_json_s
 	entry->json_source = json_str;
 	return entry;
 }
-IPAACA_HEADER_EXPORT inline PayloadDocumentEntry::ptr PayloadDocumentEntry::create_null()
+IPAACA_EXPORT inline PayloadDocumentEntry::ptr PayloadDocumentEntry::create_null()
 {
 	PayloadDocumentEntry::ptr entry = std::make_shared<ipaaca::PayloadDocumentEntry>();
-	entry->json_source = "null";
+	entry->json_source = "null"; // rapidjson::Document value is also null implicitly
 	return entry;
 }
+IPAACA_EXPORT inline PayloadDocumentEntry::ptr PayloadDocumentEntry::clone()
+{
+	return PayloadDocumentEntry::from_json_string_representation(this->json_source);
+}
+
 //}}}
 
 // PayloadEntryProxy//{{{
@@ -340,7 +381,7 @@ std::string value_diagnosis(rapidjson::Value* val)
 //
 
 /*
-IPAACA_HEADER_EXPORT template<> std::string PayloadEntryProxy::get<std::string>()
+IPAACA_EXPORT template<> std::string PayloadEntryProxy::get<std::string>()
 {
 	if (!json_value) return "";
 	//IPAACA_INFO( value_diagnosis(json_value) )
@@ -353,33 +394,33 @@ IPAACA_HEADER_EXPORT template<> std::string PayloadEntryProxy::get<std::string>(
 	
 	//return _payload->get(_key);
 }
-IPAACA_HEADER_EXPORT template<> long PayloadEntryProxy::get<long>()
+IPAACA_EXPORT template<> long PayloadEntryProxy::get<long>()
 {
 	return atof(operator std::string().c_str());
 }
-IPAACA_HEADER_EXPORT template<> double PayloadEntryProxy::get<double>()
+IPAACA_EXPORT template<> double PayloadEntryProxy::get<double>()
 {
 	return atol(operator std::string().c_str());
 }
-IPAACA_HEADER_EXPORT template<> bool PayloadEntryProxy::get<bool>()
+IPAACA_EXPORT template<> bool PayloadEntryProxy::get<bool>()
 {
 	std::string s = operator std::string();
 	return ((s=="1")||(s=="true")||(s=="True"));
 }
 // complex types
-IPAACA_HEADER_EXPORT template<> std::list<std::string> PayloadEntryProxy::get<std::list<std::string> >()
+IPAACA_EXPORT template<> std::list<std::string> PayloadEntryProxy::get<std::list<std::string> >()
 {
 	std::list<std::string> l;
 	l.push_back(PayloadEntryProxy::get<std::string>());
 	return l;
 }
-IPAACA_HEADER_EXPORT template<> std::vector<std::string> PayloadEntryProxy::get<std::vector<std::string> >()
+IPAACA_EXPORT template<> std::vector<std::string> PayloadEntryProxy::get<std::vector<std::string> >()
 {
 	std::vector<std::string> v;
 	v.push_back(PayloadEntryProxy::get<std::string>());
 	return v;
 }
-IPAACA_HEADER_EXPORT template<> std::map<std::string, std::string> PayloadEntryProxy::get<std::map<std::string, std::string> >()
+IPAACA_EXPORT template<> std::map<std::string, std::string> PayloadEntryProxy::get<std::map<std::string, std::string> >()
 {
 	std::map<std::string, std::string> m;
 	m["__automatic__"] = PayloadEntryProxy::get<std::string>();