How do I replace a substring within a string, but only if substring is matched within a regex group?
I would use two nested regexp_replace() calls:

first to enclose all keys with double quotes
then to enclose all values with double quotes


with data (input) as (
  values ('{receipt_type:Production,adam_id:1233,app_item_id:1233,more:[{h:234}]}')
)
select regexp_replace(
          regexp_replace(input, '(\w+)(:)', '&quot;\1&quot;\2', 'g'),
          '(:)(\w+)(,|})', '\1&quot;\2&quot;\3', 'g')
from data;          

returns:
{&quot;receipt_type&quot;:&quot;Production&quot;,&quot;adam_id&quot;:&quot;1233&quot;,&quot;app_item_id&quot;:&quot;1233&quot;,&quot;more&quot;:[{&quot;h&quot;:&quot;234&quot;}]}

If you want have the integers without quotes, you could run a third regexp_replace that removes the quotes from integers with quotes:
regexp_replace(..., '&quot;([0-9]+)&quot;', '\1', 'g')