If you are making a POST request from a tool like curl, and Jenkins is configured with a CrumbIssuer, you are required to obtain and pass back a valid crumb (preferably as an HTTP header) even when you are using an API token. This seems unnecessary, since the purpose of crumbs is to defend against CSRF attacks, which are possible only when the victim has a Jenkins session cookie in a browser or some browserlike client and unwittingly makes an HTTP request instigated by the attacker. But a request using basic authentication with an API token could not have come from such a client—you would not try to log in using an API token rather than using security realm-specific means, and in fact you cannot do so unless Jenkins sent a 401 response with a WWW-Authenticate header, which it almost never does.
(loginError.jelly includes a 401 response without that header, which is probably wrong. BasicAuthenticationFilter, used with the legacy security realm, does send the challenge, though this does not seem to let you actually log in using an API token either—only pass through, like ApiTokenFilter would do.)
Assuming that it is true that you cannot get a login session using an API token even if you tried, I would suggest that CrumbFilter check for req.getAttribute(ApiTokenProperty.class.getName()) instanceof User, which would be true if ApiTokenFilter has already run successfully, and in this case do nothing. (Or, for better modularity, ApiTokenFilter could implement a CrumbExclusion.) This would make the REST API significantly easier to use.