wrapUpCode always null in analytics detail query

Is there a specific filter needed to populate wrapUpCode in the detail query response?

GET /api/v2/analytics/conversations/details/query
{
 "interval": "2023-10-01T00:00:00.000Z/2023-10-02T00:00:00.000Z",
 "viewId": "conversation",
 "filter": {
 "type": "and",
 "clauses": [
 {
 "type": "field",
 "field": "wrapUpCode.id",
 "op": "eq",
 "value": "some-valid-id"
 }
 ]
 }
}

Returns 200 OK but every entity has wrapUpCode: null. The filter works for routing stats but detail view ignores it. Am I missing a segment config or is this broken?

Cause:
The issue usually boils down to how the query builder handles nested object properties versus flat attributes. When you filter on wrapUpCode.id, the engine might be excluding the full object from the projection if it doesn’t think it’s needed, or the viewId you’re using doesn’t automatically expand that specific object. It’s a common gotcha with the analytics query API. The conversation view is pretty lean by default.

Solution:
You need to explicitly tell the API to include the wrapUpCode object in the selection array. Without that, the filter might match the records (hence the 200 OK and non-zero count), but the response payload strips out the object data to save bandwidth.

Try adding a selection property to your request body. Here is how I usually structure it in the SDK or raw JSON:

{
 "interval": "2023-10-01T00:00:00.000Z/2023-10-02T00:00:00.000Z",
 "viewId": "conversation",
 "selection": [
 "wrapUpCode"
 ],
 "filter": {
 "type": "and",
 "clauses": [
 {
 "type": "field",
 "field": "wrapUpCode.id",
 "op": "eq",
 "value": "some-valid-id"
 }
 ]
 }
}

If you are using the JavaScript SDK (PureCloudPlatformClientV2), it looks like this:

const analyticsApi = platformClient.AnalyticsApi;
const queryRequest = {
 interval: '2023-10-01T00:00:00.000Z/2023-10-02T00:00:00.000Z',
 viewId: 'conversation',
 selection: ['wrapUpCode'], // <--- This is the key part
 filter: {
 type: 'and',
 clauses: [
 {
 type: 'field',
 field: 'wrapUpCode.id',
 op: 'eq',
 value: 'some-valid-id'
 }
 ]
 }
};

analyticsApi.postAnalyticsConversationsDetailsQuery(queryRequest).then(result => {
 console.log(result.body.entities[0].wrapUpCode);
});

Make sure the wrapUpCode.id you are filtering against actually exists in your org and is active. Sometimes deleted codes cause weird null returns even if the ID matches an old record.

are you sure the wrap up code was actually applied in the flow? sometimes the agent clicks ‘end’ before selecting one, leaving it null. try checking the raw conversation object via the REST API instead of analytics. analytics aggregates can be slow to reflect real-time state. here’s a quick check:

GET /api/v2/conversations/voice/{conversationId}

look at the wrapUp field there.

The suggestion about checking the raw conversation object is spot on, but there’s a deeper issue with how you’re querying analytics. The conversation view doesn’t always expand nested objects like wrapUpCode by default, especially if the filter syntax isn’t quite right. You’re filtering on wrapUpCode.id, but the analytics engine might not be jecting the full object back because it thinks you only need the ID match.

Try explicitly selecting the field in the query to force the jection. Also, double-check that the wrap-up code was actually saved on the interaction. Agents often click “Complete” without selecting a code, leaving it null. Here’s a tweaked query to force the field inclusion:

{
 "interval": "2023-10-01T00:00:00.000Z/2023-10-02T00:00:00.000Z",
 "viewId": "conversation",
 "select": ["wrapUpCode.id", "wrapUpCode.name"],
 "filter": {
 "type": "and",
 "clauses": [
 {
 "type": "field",
 "field": "wrapUpCode.id",
 "op": "eq",
 "value": "some-valid-id"
 }
 ]
 }
}

If that still returns null, check the raw API endpoint /api/v2/conversations/voice/{id} to see if the code was actually saved. Analytics data can lag, but raw data is immediate.