Please don't use changesets to enforce some kind of type system between system components. In case you do not trust your own code, Elixir is strongly typed (though not static typed), there are test cases, there's dialyxir and if still you cannot stop yourself from passing a number where a string will do, the process will crash, log a message for you to fix the bug, and get restarted by a supervisor.
I get why people are obsessed with static typing on "normal" languages, where bugs cause system downtime, but the Erlang platform gives you so many guarantees that even if you somehow make a mistake, it is never catastrophic. Gradual typing in Elixir is a nice cherry on top of the runtime, not the cornerstone to robust OTP software.
The runtime costs aren’t trivial, especially on large datasets, but I’ve come to love this pattern a lot.