You often don't need or want cross service atomicity, just eventual consistency. Each microservice should be an idempotent state-machine where it expects to have atomic commits to it's own state but never expects to be able to conduct a transaction across the service boundary. However, services can conduct local transactions on their own state joined against a read-only cached copy of another service's state - you can implement this with an event bus or a shared caching tier. This can allow you to avoid writing your own joining logic and use standard ORMs. Ensuring the queues are flowing and retries happen is very important though, you need to monitor queue lengths and job errors to ensure the eventual part of eventual consistency is happening.
For this particular example createAccount would create a local commit with a state of CREATING, returns an account_id and asynchronously creates jobs to complete the billing, the auth, whatever. You then have a job that is polling in the background to move the account to CREATED once all or enough of the dependencies are successful(i.e you may have a slow third party provider you don't want to block on). Your front end polls the state of the account and displays a pretty animation to distract the user while you do the work.