When yout Ctrl-C in the terminal, SIGINT is sent to all the processes that belong to the foreground process group id (TPGID). (The same is true for any signals generated by the keyboard: SIGTSTP, SIGINT, etc.)
To find the TPGID, you can ps -O tpgid. For example, if I run ser bin/dev in a Rails app (ser is a local reverse-proxy I wrote):
PID TPGID TT STAT TIME COMMAND
1444 2822 s000 S 0:00.90 -zsh
2822 2822 s000 S+ 0:01.68 /Users/riccardoodone/.rvm/gems/ruby-3.4.4/gems/ser-0.1.0-x86_64-darwin/exe/x86_64-darwin/ser bin/dev
3484 2822 s000 S+ 0:00.64 foreman: main
3509 2822 s000 S+ 0:06.32 puma 7.0.4 (tcp://localhost:3000) [rictionary]
3510 2822 s000 S+ 0:12.17 sidekiq 8.0.8 rictionary [0 of 7 busy]
3535 2822 s000 S+ 0:00.10 puma: cluster worker 0: 3509 [rictionary]
3536 2822 s000 S+ 0:00.10 puma: cluster worker 1: 3509 [rictionary]
3537 2822 s000 S+ 0:00.11 puma: cluster worker 2: 3509 [rictionary]
3538 2822 s000 S+ 0:00.10 puma: cluster worker 3: 3509 [rictionary]
3539 2822 s000 S+ 0:00.10 puma: cluster worker 4: 3509 [rictionary]
3540 2822 s000 S+ 0:00.10 puma: cluster worker 5: 3509 [rictionary]
If you wanted to simulate a Ctrl-C programmatically, you could send a signal to the -TPGID (minus means process group):
kill -INT -2822
More details in this wonderful Stack Overflow answer.