The routes are matched in sequence. Your constraint: new { id = @"\d+" } on the 3rd route isn't getting a look-in because the 2nd route will always win.
So swap your 2nd and 3rd routes around.
Always put the most selective routes at the top.
config.Routes.MapHttpRoute(
name: "ControllerActionIdApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { },
constraints: new { id = @"\d+" }
);
//
config.Routes.MapHttpRoute(
name: "ControllerIdApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { },
constraints: new { id = @"\d+" }
);
//
config.Routes.MapHttpRoute(
name: "ControllerActionApi",
routeTemplate: "api/{controller}/{action}"
);
//
config.Routes.MapHttpRoute(
name: "ControllerApi",
routeTemplate: "api/{controller}"
);