TLDR
It is not possible to prevent communicate with your API through different (cloned) clients guaranteed way in cases when white-lists of IP addresses can't/shouldn't be used.
Why
Think about it that way. You have a server that has some identification rule - client should have some identifier that marks it as trusted. In your question it is a domain.
Domain is a public information that could be passed in HTTP header or in the body of your request, it is easy, but also it will be easy for clients to replace this information on their side.
And if you use any type of cryptography to provide more secured identification mechanism - you just making it harder to hack it and again pretend as trusted client, because every mechanism you use on the client side could be reverse-engineered by a hacker. Just look at this question.
One think you can use to guaranteed access restriction is to use white-list of IP addresses on server-side, because IP address is a part of TCP/IP transport level protocol and it has "handshake" process to identify communicated points to each other, and it is kind of hard to replace it. Check this question for details.
So what can you do?
CORS
Setup CORS policy is a first step to create a trusted client-server communication. Most of browsers are support CORS policies, but of course client may be not a browser. And the questions was not about browser-server communication, but I should mention that because browser is a client too.
Client-side encryption
You can use encryption, but I don't see any reason to do that because any request to server could be read through your legal client (website). So even if you encrypted it - any person has a key and a crypto algorithm on their side to pretend as trusted client. But if you want to...
You need to create unique key every your request to make life of pretenders little harder. To make it you need few ingredients:
- Public key for key generation (encrypted) on the client side
- Obfuscated key generation JS code
- Private key for decrypt generated key on the server side
JS-side RSA crypto libraries could be googled easily (for example)
Obfuscation libraries could be found just using google too (like this)
Server-side decryption could be done with System.Security.Cryptography
namespace if you use C# backend.
Basically, more complex key-generation algorithm you make and more obfuscated code you make - more hard for hacker to pretend himself as a trusted client. But as I said there is no guaranteed way to completely identify trusted client.