When two components interact they need to use the same interface, one as provider of data and one as consumer. It does not matter if you talk about a REST API, function call, or Protobuf definition, one problem is always the same: Who owns the interface? In most cases, there is an intuitive answer but the remaining cases lead to lots of discussions and meetings because thou shalt partition software with respect to Conway's Law.
There are exactly three ways to structure ownership. If you use an interface it is owned above, below, or at the same layer.
If the interface is owned by a lower layer, it is easy to connect two components on the same layer with the interface: Both depend on the lower layer and use it. The downside of this approach is the loss of agility. Modifying the interface requires a (usually breaking) change in a lower layer and every user has to fix the breakage.
If the interface is on the same layer, it can evolve more quickly. The owner can change the interface even atomically together with feature extensions. We can use dependency inversion to move ownership between components. The downside is that it introduces coupling and thus requires additional coordination between the components. The components lose independence although they are on the same layer.
Also, it may happen that with multiple interfaces a dependency cycle is created across components.
Finally, the interface may be owned by the layer above. We could also describe it as the refusal to share an interface between components who need a connection. The implication is that the user has to insert an adapter. This provides ultimate flexibility as different users can use different adapters. The downside is a loss of efficiency. An adapter requires maintenance and validation effort, runtime and other resources.
None of the three is perfect. It always requires a trade-off. Whenever you discuss about such ownership, check if you considered all three options.