Ok, so I got it working with nom and the extended URL format api/v1/rooms/UUID/tracks/UUID.
The basics are the same as before: you want to check for eof, ignore trailing "/" and never wait for incomplete results (alt_complete! is doing a good job here).
Regarding your ErrorKind::Verify wish: I don't think the error kind is actually important, just ignore it, or map it to whatever you want manually.
Be careful with the alt_complete! branches: in case of overlaps the preferred option (usually the "longer one") should come first.
I like my with! helper, but you could also inline it.
Playground doesn't support nom, so no link this time.
#[macro_use]
extern crate nom;
extern crate uuid;
use uuid::Uuid;
named!(uuid<&str, Uuid>, preceded!(
    tag_s!("/"),
    map_res!(take_s!(36), str::parse)
));
#[derive(Clone, PartialEq, Eq, Debug)]
enum ApiRequest {
    Rooms,
    Room { room: Uuid },
    Tracks { room: Uuid },
    Track { room: Uuid, track: Uuid },
}
/// shortcut for: `do_parse!(name: expr >> r: otherexpr >> (r))`
///
/// `otherexpr` should use `name`, otherwise you could just use `preceded!`.
macro_rules! with {
    ($i:expr, $var:ident: $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
        do_parse!($i, $var: $submac!($($args)*) >> r: $($rest)* >> (r));
    };
    ($i:expr, $var:ident: $submac:ident >> $($rest:tt)*) => {
        do_parse!($i, $var: $submac >> r: $($rest)* >> (r));
    };
}
// /api/v1/rooms/UUID/tracks/UUID
named!(apiv1<&str, ApiRequest>, preceded!(tag_s!("/api/v1"),
    alt_complete!(
        preceded!(tag_s!("/rooms"), alt_complete!(
            with!(room: uuid >> alt_complete!(
                preceded!(tag_s!("/tracks"), alt_complete!(
                    with!(track: uuid >> alt_complete!(
                        // ... sub track requests?
                        value!(ApiRequest::Track{room, track})
                    ))
                    |
                    value!(ApiRequest::Tracks{room})
                ))
                // other room requests
                |
                value!(ApiRequest::Room{room})
            ))
            |
            value!(ApiRequest::Rooms)
        ))
        // | ... other requests
    )
));
named!(api<&str, ApiRequest>, terminated!(
    alt_complete!(
        apiv1
        // | ... other versions
        // also could wrap in new enum like:
        //     apiv1 => { ApiRequest::V1 }
        //     |
        //     apiv2 => { ApiRequest::V2 }
    ),
    tuple!(
        alt_complete!(tag_s!("/") | value!("")), // ignore trailing "/"
        eof!() // make sure full URL was parsed
    )
));
fn main() {
    use nom::IResult::*;
    use nom::ErrorKind;
    let room = Uuid::parse_str("e19c94cf-53eb-4048-9c94-7ae74ff6d912").unwrap();
    let track = Uuid::parse_str("83d235e8-03cd-420d-a8c6-6e42440a5573").unwrap();
    assert_eq!(api("/api/v1/rooms"), Done("", ApiRequest::Rooms));
    assert_eq!(api("/api/v1/rooms/"), Done("", ApiRequest::Rooms));
    assert_eq!(
        api("/api/v1/rooms/e19c94cf-53eb-4048-9c94-7ae74ff6d912"),
        Done("", ApiRequest::Room { room })
    );
    assert_eq!(
        api("/api/v1/rooms/e19c94cf-53eb-4048-9c94-7ae74ff6d912/"),
        Done("", ApiRequest::Room { room })
    );
    assert_eq!(
        api("/api/v1/rooms/e19c94cf-53eb-4048-9c94-7ae74ff6d912/tracks"),
        Done("", ApiRequest::Tracks { room })
    );
    assert_eq!(
        api("/api/v1/rooms/e19c94cf-53eb-4048-9c94-7ae74ff6d912/tracks/"),
        Done("", ApiRequest::Tracks { room })
    );
    assert_eq!(
        api("/api/v1/rooms/e19c94cf-53eb-4048-9c94-7ae74ff6d912/tracks/83d235e8-03cd-420d-a8c6-6e42440a5573"),
        Done("", ApiRequest::Track{room, track})
    );
    assert_eq!(
        api("/api/v1/rooms/e19c94cf-53eb-4048-9c94-7ae74ff6d912/tracks/83d235e8-03cd-420d-a8c6-6e42440a5573/"),
        Done("", ApiRequest::Track{room, track})
    );
    assert_eq!(api("/api/v1"), Error(ErrorKind::Alt));
    assert_eq!(api("/api/v1/foo"), Error(ErrorKind::Alt));
    assert_eq!(api("/api/v1/rooms/123"), Error(ErrorKind::Eof));
    assert_eq!(
        api("/api/v1/rooms/e19c94cf-53eb-4048-9c94-7ae74ff6d912/bar"),
        Error(ErrorKind::Eof)
    );
    assert_eq!(
        api("/api/v1/rooms/e19c94cf-53eb-4048-9c94-7ae74ff6d912/tracks/83d235e8-03cd-420d-a8c6-6e42440a5573/123"),
        Error(ErrorKind::Eof)
    );
    assert_eq!(api("/api/v2"), Error(ErrorKind::Alt));
}
You could also use a more strict alt_full_opt_slash! branch method, which would ensure a branch only matches if it fully parsed the input.
You could then use a more "flat" way (although nested branches should still be working) to parse the alternatives (although this means you might end up parsing some UUIDs more than once; also now all errors are of kind Alt):
/// Similar to alt_complete, but also requires the branch parses until
/// the end of the input (but ignores a trailing "/").
macro_rules! alt_full_opt_slash {
    (__impl_push2 ($i:expr,) ($($new:tt)*), $($rest:tt)*) => {
        alt_full_opt_slash!(__impl ($i, $($new)*), $($rest)*)
    };
    (__impl_push2 ($i:expr, $($result:tt)+) ($($new:tt)*), $($rest:tt)*) => {
        alt_full_opt_slash!(__impl ($i, $($result)+ | $($new)*), $($rest)*)
    };
    (__impl_push ($($result:tt)*) ($($new:tt)*), $($rest:tt)*) => {
        // modify branch:
        alt_full_opt_slash!(__impl_push2 ($($result)*) (
            terminated!(
                $($new)*,
                tuple!(
                    alt_complete!(tag_s!("/") | value!("")), // ignore trailing "/"
                    eof!() // make sure full URL was parsed
                )
            )
        ), $($rest)*)
    };
    (__impl ($($result:tt)*), $e:ident | $($rest:tt)*) => {
        alt_full_opt_slash!(__impl_push ($($result)*) ( $e ), $($rest)*)
    };
    (__impl ($($result:tt)*), $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => {
        alt_full_opt_slash!(__impl_push ($($result)*) ( $subrule!($($args)*) ), $($rest)*)
    };
    (__impl ($($result:tt)*), $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)*) => {
        alt_full_opt_slash!(__impl_push ($($result)*) ( $subrule!($($args)*) => { $gen } ), $($rest)*)
    };
    (__impl ($($result:tt)*), $e:ident => { $gen:expr } | $($rest:tt)*) => {
        alt_full_opt_slash!(__impl_push ($($result)*) ( $e => { $gen } ), $($rest)*)
    };
    (__impl ($i:expr, $($result:tt)*), __end) => {
        alt_complete!($i, $($result)*)
    };
    ($i:expr, $($rest:tt)*) => {{
        alt_full_opt_slash!(__impl ($i, ), $($rest)* | __end)
    }};
}
// /api/v1/rooms/UUID/tracks/UUID
named!(apiv1<&str, ApiRequest>, preceded!(tag_s!("/api/v1"),
    alt_full_opt_slash!(
        do_parse!(
            tag_s!("/rooms") >>
            (ApiRequest::Rooms)
        )
        |
        do_parse!(
            tag_s!("/rooms") >>
            room: uuid >>
            (ApiRequest::Room{room})
        )
        |
        do_parse!(
            tag_s!("/rooms") >>
            room: uuid >>
            tag_s!("/tracks") >>
            (ApiRequest::Tracks{room})
        )
        |
        do_parse!(
            tag_s!("/rooms") >>
            room: uuid >>
            tag_s!("/tracks") >>
            track: uuid >>
            (ApiRequest::Track{room, track})
        )
    )
));
named!(api<&str, ApiRequest>, alt_complete!(
    apiv1
    // | ... other versions
    // also could wrap in new enum like:
    //     apiv1 => { ApiRequest::V1 }
    //     |
    //     apiv2 => { ApiRequest::V2 }
));