Asking for a state would require a new field in UI and DB that is filled only on Americans. I'd like to avoid it, since the state can be determined by the ZIP code that has to be entered, too.
You're basically relying on another database if you're trying to get a state from a zip code. That would add a bit more latency to your web application because your script that processes the zip code in the registration form will have to make a call to a special server that retrieves the correct state from the database.
I'm sorry if you won't agree with this, but I recommend not avoiding that extra field. Instead, you should add it as a 2-character field to represent the short form of the state because there is a chance that the correct state could not be found based on a given zip code. Also with this method, the latency is substantially lower since you won't have to lookup the state on the special server every time you want the state since its right there in the database.
Personally, I'd rather waste two bytes per applicant to hold the american state information rather than waste several hundred extra milliseconds to lookup the state based on the zip code every time the state is required.
Otherwise the correct procedure could be to set up an SQL trigger to make sure that field cannot be set on non Americans
No need. If you add the field for the state, and the applicant is a non-american, then use a value in the field that doesn't represent a real state. For example, "XX". Then you can use simple SQL SELECT statements to find applicants based on states, and for non-americans, if you follow my example, and you want non-americans, your SQL statement would be something similar to:
SELECT customer,address,state,zip FROM customers WHERE state = "XX";
But then again, it depends on your fields. In my example, I assumed your table is named "customers" and the fields are customer, address, state, and zip.