In my tests, utils.json.fromJson seems to be working.
You shouldn't need to add the ?('UTF-8') to the http.request.body call, as it returns the body as a UTF-8 encoding string already.
You might want to try something like this for your endpoint:
<#function doRestV1Call uri admin=false>
<#if admin>
<#assign restCall = restadmin />
<#else>
<#assign restCall = rest />
</#if>
<#return restCall(uri) />
</#function>
<#function setProfileField ssoId name val admin=false>
<#return doRestV1Call("/users/sso_id/" + ssoId + "/settings/name/" + name + "/set?value=" + val, true) />
</#function>
<#function setCertInfo ssoId val>
<#return setProfileField(ssoId, "profile.cert_info", val?url, true) />
</#function>
<#function getCertInfo ssoId>
<#return doRestV1Call("/users/sso_id/" + ssoId + "/settings/name/profile.cert_info", true).value />
</#function>
<#assign errorMsg = "" />
<#if ("POST" == http.request.method)>
<#attempt>
<#assign alpha = http.request.body />
<#if alpha?? && alpha?has_content && alpha?is_string>
<#assign alpha = utils.json.fromJson(alpha) />
<#assign updateProfile = setCertInfo(alpha.id, "L1" + alpha.id) />
<#elseif alpha?? && alpha?has_content && alpha?is_hash>
<#-- this should not happen -->
<#assign updateProfile = setCertInfo(alpha.id, "L2") />
<#else>
<#assign errorMsg = "no request body" />
</#if>
<#recover>
<#assign errorMsg = .error />
</#attempt>
<#if errorMsg?length lt 1>
<#attempt>
<#assign profileVal = getCertInfo(alpha.id) />
<#recover>
<#assign errorMsg = .error />
</#attempt>
</#if>
<#else>
<#assign errorMsg = "request must be an HTTP POST." />
</#if>
<#if errorMsg?length gt 0>
{
"successful": false,
"message": "${errorMsg?json_string}"
}
<#else>
{
"successful": true,
"message": "profile updated",
"value": "${profileVal?json_string}"
}
</#if>
-Doug