php cURL having issues with special characters in passwords

I’m encountering an issue with 2 separate API providers who are insisting this is a problem in our code. Maybe so, but I am not sure what else I need to do here.

Say a user has a password of abc%123. Normally when posting with cURL it handles the encoding.

The cURL code is pretty straight forward:

    $params = [
      'userid' => $_POST['username'],
      'userpw' => $_POST['password']
    ];
    $url = 'https://api-service.com/whatever';
    $curl = curl_init($url);
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

    $headers = array("Content-Type: application/json");
    curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
    
    $data = json_encode(array('data' => $params));
    
    curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
    
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, true);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
    
    $resp = curl_exec($curl);
    curl_close($curl);
    
    $response = json_decode($resp);

The error I get back, which is specific to the services, more or less say “The submission failed because it contained non-standard characters. Please contact the website administrator to request that they update the settings to allow submission of non-standard characters.”

It sounds like they are asking for the password to be urlencoded. When I do that, it accepts the transport, but then errors saying the password is incorrect as though it is literally reading my posted password as “abc%25123”

Am I missing something here? Some cURL setting or header setting that I just somehow didn’t know about after all these years? To me this seems like the service is disallowing special characters and they need to handle that case, but they both separately insist this is not the case. Any ideas?