To save a metadata to a line_item (product that is in a order), you can hook the woocommerce_new_order_item action.
Hook it like this:
function my_line_item_metadata( $item_id, $item, $order_id ) {
// Here you have the item, his id, and the order's id
// You can get the order, for example
$order = new WC_Order( $order_id );
$items = $order->get_items();
foreach( $items as $line_item_id => $item ) {
// Here you can have all products from the order!
}
// Save here the metadata for the item id of the hooked line item
wc_add_order_item_meta( $item_id, '_my_metadata', 'my metadata value' );
}
add_action( 'woocommerce_new_order_item', 'my_line_item_metadata', 10, 3 );
As you said that you using the WC API, you maybe want to add this field to the API return... to do it, use the following code:
/**
* Add order meta to the REST API
* @see http://codegists.com/code/order%20item%20meta%20rest%20response/
*
* @param \WP_REST_Response $response The response object.
* @param \WP_Post $post Post object.
* @param \WP_REST_Request $request Request object.
* @return object updated response object
*/
function my_add_metadata_on_line_item( $response, $post, $request ) {
$order_data = $response->get_data();
foreach ( $order_data['line_items'] as $key => $item ) {
$order_data['line_items'][ $key ]['_my_metadata'] = wc_get_order_item_meta( $item['id'], '_my_metadata', true );
}
$response->data = $order_data;
return $response;
}
add_filter( 'woocommerce_rest_prepare_shop_order', 'my_add_metadata_on_line_item', 10, 3 );
Now your API will return the _my_metadata with the line item.
PS.: If you don't save your custom metadata with the _, WC will show the metadata in some places that you may not want to. With the _ the metadata will be hidden.