You’re getting that mismatched values because you’re using the wrong argument for the post ID in your $args array (i.e. the query args for WP_Query). And the correct argument is p (lowercase P) and not id:
$args = [
// 'id' => $request['id'], // wrong argument name - 'id'
'p' => $request['id'], // and the correct one is 'p'
'post_type' => 'payment',
];
And in addition to that main issue, another one I noticed is the $post_id = $post->ID; whereby that $post is an array and not object. So did you mean to use $post_id = $post[0]->ID; ?
Also, why do you have to use get_posts()? Why not just use get_post() — $post = get_post( $request['id'] ); ? That way, the above $post_id = $post->ID; would be valid. So for example, this is how your code would look like when using get_post():
if ( ! $post = get_post( $request['id'] ) ) {
return new WP_Error( 'your_error_code_here', 'Please define a valid post ID.' );
}
$metas = get_post_meta( $request['id'] );
$post_id = $post->ID;
$response[ $post_id ]['response'] = $post;