Here is the envelope structure I use for my JSON messages.
{
    "message_id":"message_id_000001",
    "status":"[SUCCESS|ERROR|WARNING]",
    "status_code":"[200|404|500|etc]",
    "messages":[
        {
            "message_order":"1",
            "message_type":"[ERROR|WARNING|INFO|DEBUG|TRACE]",
            "message_format":"[HTML|TEXT]",
            "message":"message text here"
        },
        {
            "message_order":"2",
            "message_type":"[ERROR|WARNING|INFO|DEBUG|TRACE]",
            "message_format":"[HTML|TEXT]",
            "message":"message text here"
        }
    ],
    "data":[
        {
            "data_1":"data 1"
        },
        {
            "data_2":"data 2"
        }
    ]
}

The structure is pretty verbose, it's almost like using SOAP XML calls...almost. The important point for me, is that I can easily debug the JS code my application is processing. I still have not figured out the security part though. Most of the time I actually forget (I'm getting old!) what the actual structure of my response is, so I just create a handy class based on a HashMap. Why a HashMap? Because I do not know what other data may be required for transmission to other clients. This way I can add them without having to upgrade everything else.

Here's the class I use:
package info.markhansen.json;

import java.rmi.server.UID;

import java.util.Collection;
import java.util.HashMap;
import java.util.TreeMap;

public class JsonEnvelope extends HashMap {
 public static final String STATUS = "status";
 public static final String STATUS_CODE = "status_code";
 public static final String DATA = "data";
 public static final String MESSAGES = "messages";
 public static final String MESSAGE_ID = "message_id";
 
 public JsonEnvelope() {
  // Create a unique ID for this message
  this.put(MESSAGE_ID, new UID());
  // Make sure the messages array is not null
  this.put(MESSAGES, new TreeMap());
  // Set the default status to success
  this.setStatusOther("SUCCESS");
  // set the default status code to success
  this.setStatusCode(200);
 }
 
 public String getMessageId() {
  return (String)this.get(MESSAGE_ID);
 }
    
 public void setStatusSuccess() {
  this.setStatusOther("SUCCESS");
 }
 
 public void setStatusError() {
  this.setStatusOther("ERROR");
 }
 
 public void setStatusOther(String status) {
  this.put(STATUS, status);
 }
 
 public void setStatusCode(int statusCode) {
  this.put(STATUS_CODE, new Integer(statusCode));
 }
 
 public void setData(Collection data) {
  this.put(DATA, data);
 }
 
 public void setMessages(TreeMap messages) {
  if (null != messages) {
      this.put(MESSAGES, messages);
  }
 }
 
 public void addMessage(String message) {
  final TreeMap messages = (TreeMap)this.get(MESSAGES);
  messages.put(new Integer(messages.size() + 1), message);
 }
}


Usually when working on the interface for an application, there are multiple items which require an $.ajax call of some sort. Auto Complete fields, tables, drop downs, combo boxes, you get the idea. Now, before I learned about JQuery deferred objects, I would have an $.ajax call inside of my event handler methods. I know it's not the best way, but it's the most straightforward way I could implement it when I first began to use JQuery. The code ended up looking like the following:

cmdAddUser.click(function () {
var useridToAdd = $("#newUserIdToAdd").val();
var messageContainer = $("#messageContainer");
$.ajax({
type: "POST",
url: "/service/users/add",
dataType: "json",
data: {
userid: useridToAdd
},
success: function (data) {
var statusCode = data.response.status_code;
messageContainer.html('');
switch (statusCode) {
case "200":
messageContainer.addClass('ui-state-highlight');
messageContainer.html('<ul><li>' + data.response.status_message + '</li></ul>');
break;
default:
var messages = '<ul>';
$.each(data.response.errors, function (index, value) {
messages += '<li><pre>' + value + '</pre></li>';
});
messages += '</ul>';
messageContainer.html(messages);
break;
}
},
error: function (xhr, s, e) {
alert(s.error_status);
}
});
});

That's a pretty ugly snippet of code.

However, with the Deferred Objects introduced in JQuery 1.5 I can clean up that code:
function addUser(messagesContainer, newUserParameters) {
return $.post('/service/users/add', newUserParameters).error(function (xhr) {
var jsonData = $.parseJSON(xhr.responseText);
// this is a generic error reporting function
reportErrors(messagesContainer, jsonData.response.errors);
});
};

cmdAddUser.click(function () {
var useridToAdd = $("#newUserIdToAdd").val();
var messageContainer = $("#messageContainer");
var c = addUser(messageContainer, {
userid: useridToAdd
});
c.success(function (data) {
messageContainer.addClass('ui-state-highlight');
messageContainer.html('<ul><li>' + data.response.status_message + '</li></ul>');
});
});
With the $.ajax call isolated, I can now use this call in multiple places through out the site without having to repeat the code. It's nice and DRY (Don't Repeat Yourself...Dum Dum) now.