This is more of a database best practice than R best practice
You did not mention what database backend you are using, and it is certain that the optimal solution will vary somewhat. The code below is using Postgres dialect.
In general I would suggest using two tables - let us call them a staging layer and core layer.
I would start by truncating the stage layer
dbSendQuery(con, "truncate table stg_api_results")
Then insert values of the current apis
db_insert_into(con, "stg_api_results", values = frm_API_values)
And lastly flip the stage over to core via
dbSendQuery(con, "insert into api_results
select * from stg_api_results
on conflict (serial_no) do update
set updated_time = current_timestamp")
Also worth considering (though likely not in your use case) is
on conflict do nothing, variant which is helpful in enforcing unique values (only new rows are inserted).
I am assuming an unique constraint on the field serial_no.