Promise.all over 2,400 sends is 2,400 concurrent requests, so you did not hit the limit halfway, you hit it immediately and 600 happened to squeak through before the bucket emptied. The default is around 2 requests a second on most plans.
Two changes. Use the batch endpoint instead of one call per recipient, it takes up to 100 messages per request, so 2,400 people is 24 calls, not 2,400. And write the send state before you send, not after:
UPDATE subscribers SET state='claimed', batch_id=$1
WHERE id = ANY($2) AND state='pending'
RETURNING id
Only send the rows that come back from the RETURNING. Now the process can die anywhere and a re-run picks up exactly what is left, and nobody gets two copies.