I\'m receiving a JSON object from a public API with a property that, itself, is an escaped JSON string.
{
   \"responses\":[
      {
         \"info\":\"keep         
        
Your JSON contains a literal string for the "body" objects that is actually embedded, double-serialized JSON.  To deserialize this to a POCO hierarchy without needing to introduce an intermediate string Json surrogate property inside any of your types, you have a few options:
You could preprocess your JSON using LINQ to JSON and replace the literal "body" strings with their parsed equivalents:
    var rootToken = JToken.Parse(json);
    foreach (var token in rootToken.SelectTokens("responses[*].body").ToList().Where(t => t.Type == JTokenType.String))
    {
        token.Replace(JToken.Parse((string)token));
    }
    var root = rootToken.ToObject();
 You could introduce a generic JsonConverter for the POCO corresponding to each Body object that parses the incoming embedded JSON string literal into a LINQ to JSON hierarchy, then deserializes that:
public class EmbeddedLiteralConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(T).IsAssignableFrom(objectType);
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var contract = serializer.ContractResolver.ResolveContract(objectType);
        if (contract is JsonPrimitiveContract)
            throw new JsonSerializationException("Invalid type: " + objectType);
        if (existingValue == null)
            existingValue = contract.DefaultCreator();
        if (reader.TokenType == JsonToken.String)
        {
            var json = (string)JToken.Load(reader);
            using (var subReader = new JsonTextReader(new StringReader(json)))
            {
                // By populating a pre-allocated instance we avoid an infinite recursion in EmbeddedLiteralConverter.ReadJson()
                // Re-use the existing serializer to preserve settings.
                serializer.Populate(subReader, existingValue);
            }
        }
        else
        {
            serializer.Populate(reader, existingValue);
        }
        return existingValue;
    }
    public override bool CanWrite { get { return false; } }
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}
  
Then use it like:
    var root = JsonConvert.DeserializeObject(json, new EmbeddedLiteralConverter());
 
Note that the converter checks to see whether the incoming JSON token is a string, and if not, deserializes directly.  Thus the converter should be usable when the "body" JSON is and is not double-serialized.
For testing purposes I generated the following target classes using http://json2csharp.com/:
public class Error
{
    public string message { get; set; }
    public string type { get; set; }
    public int code { get; set; }
}
public class Body
{
    public Error error { get; set; }
}
public class Respons
{
    public string info { get; set; }
    public Body body { get; set; }
}
public class RootObject
{
    public List responses { get; set; }
}