In another much more generic customer facing API I instead used a custom schema, as I needed to do other things that would not have been possible in it like embedding the API documentation in the schema so the front-end could display help on-the-fly and use the schema to dynamically generate forms. The advantage was also that being fully in control of the syntax I could create ways to express constraints like field X is valid only in searches, field Y is valid only in PUT/PATCH but not POST, etc. etc.
This said especially for straightforward APIs I feel JSON schemas are quite useful, being able to have a single source of truth on what your messages look like that you can share with front-end, back-end and customers is quite powerful. One thing is though that validation errors are not very user-friendly unfortunately. This was all around draft-04 time IIRC.