Single quotes is a literal string in groovy, so it will literally be {"text": " ${msg}"} so already it feels like not doing what you are expecting it to do.
I would recommend using environmental variables and let bash handle all the escaping for you. Since you are already in a script {} tag, withEnv is cleanest
def msg = "## ${logEnvironmentTAG} :white_check_mark:\n${JOB_NAME}\n${BUILD_URL}\nRequester: ${Jenkins_username}\n\n|GIT|Log|Commit ID|\n|---|---|---|\n|ID|${lastCommitLog_escaped}|${lastCommitHash}|\n|ENV|${lastCommitEnvLog_escaped}|${lastCommitEnvHash}|"
# note double quotes on the first one so groovy with evaluate variables
withEnv(["JSON=${writeJSON(returnText: true, json: ['text': msg]}"]) {
sh(script: '''curl ${CURL_OPTS} -i -X POST \
-H 'Content-Type: application/json; charset=utf-8' \
--data "${JSON}" \
${URL}''')
}
using triple single quotes will allow you to use single quotes inside of bash without issue. Using double quotes inside of the shell statement will tell bash to escape the variable, and using the JSON env variable will prevent you from having to do all the escaping.