PATCH /api/v2/conversations/participants failing with 409 Conflict when updating attributes mid-call

I’m hitting a wall trying to update participant attributes for an active voice conversation using the .NET SDK (Genesys Cloud Platform SDK v126.0.0). The goal is to sync our internal CRM’s lead score back to Genesys Cloud so the agent sees it in the sidebar without hanging up the call.

Here is the relevant C# snippet running in an Azure Function triggered by a webhook:

var participantId = "some-participant-id";
var conversationId = "some-conv-id";

var patch = new ConversationParticipantPatchRequest
{
 Attributes = new Dictionary<string, object>
 {
 { "crm:leadScore", 85 },
 { "crm:status", "Qualified" }
 }
};

try
{
 var response = await _conversationsApi.ConversationsParticipantsPatchAsync(
 conversationId,
 participantId,
 patch
 );
 Console.WriteLine($"Updated: {response.StatusCode}");
}
catch (ApiException ex)
{
 Console.WriteLine($"Error: {ex.ErrorCode} - {ex.Message}");
 Console.WriteLine($"Body: {ex.ResponseAsString}");
}

The docs for PATCH /api/v2/conversations/participants/{participantId} state that you can patch attributes. It says: “Update a participant in a conversation. This allows for updating attributes, role, or other participant-specific properties.”

But every time I call this while the call is active (status: connected), I get a 409 Conflict. The error message is generic: “Conflict. The resource you are trying to update is currently locked or in an invalid state for this operation.”

I’ve checked the trace logs. The participant ID is correct. The conversation ID is correct. I can read the participant data fine with a GET request right before the PATCH. It only fails when the call is active. If I wait for the call to end and try the PATCH, it works fine (though it’s useless then).

Is there a specific attribute naming convention I’m missing? Or does the .NET SDK serialize the ConversationParticipantPatchRequest differently than the spec expects? I tried sending raw JSON via HttpClient directly just to test, same 409 result.

The header Prefer: codes=100 returns the same conflict. Am I supposed to use the conversationId and participantId from the initial invite object or the one generated after accept? I’m using the one from the conversation.participants array after the state changes to connected.