I have an API that sends webhooks/callbacks to a client, but not as a response to a previous API call, such as requesting async data or making a subscription. The "subscribe" step happens elsewhere, through a web frontend, so there is no path entry in the API spec for me to put my callback entries under.
I would like to have callback items in my spec but they need to be independent of any previous API call since in this case I don't have one. Is there a recognised workaround for this? Or would we need a formal spec change to accommodate this? I'd really appreciate any advice!
My use case: the Nexmo SMS API allows users to make an API call to send a message. When they sign up for an API key and secret, they configure a URL to receive webhooks when an SMS arrives at this number. So the incoming webhook is not really a callback, and doesn't belong to a previous API call. I have also been asked how this works by a few other organisations looking to move to OpenAPI (I have given a few conference talks about OpenAPI) and I'd love to have a good answer myself and to offer to otthers.
I got some positive noise in response to this on slack so I created a format proposal for adding webhooks https://github.com/OAI/OpenAPI-Specification/pull/1974. I'd still love to hear any advice or comments you have either on this issue or over on the proposal
@lornajane How about putting the callbacks in /components/callbacks? This allows you to describe the webhook without attaching it to a path. We could consider adding an optional property to a callback to indicate that it could be registered out of band.
Regarding the proposal, I can see the value of adding a new key to describe between callbacks that are registered out of band, however, I wouldn't want to use the term webhook to make that distinction as most implementations of webhooks are registered by subscribing to an API.
Thanks @darrelmiller ! I am not sure I agree that "most implementations of webhooks are registered by subscribing to an API". The ones I've used have almost all been a website setup step to configure the destination URL rather than an API call. Maybe I'm just using the wrong APIs ? :)
I don't feel strongly about naming or structure, I really just need the feature of being able to describe the incoming requests from server to API client. To me it seems like these are equivalent to (but distinct from) the entries in paths that describe the requests which is why I proposed the sibling entry to that entry. If some other name or structure would help this to be acceptable so that I could continue to use OpenAPI, that would also be fine!
@lornajane What about describing the webhook callbacks in /components/callbacks? That way you don't have to have a path.
@darrelmiller
@lornajane What about describing the webhook callbacks in /components/callbacks? That way you don't have to have a path.
Possibly with a new flag such as [registered]outOfBand: true to prevent the case where some validators / linters complain about objects under components which are not referenced elsewhere in the OpenAPI doc?
I think that it would be better to recognise webhooks alongside outgoing API calls and callbacks. Or I guess just be up front that we don't want to support these types of 2-way APIs? Putting something nested in components that isn't referred to from the main OpenAPI doc structure doesn't feel like first-class feature support to me, sorry.
My challenge is that callbacks are webhooks. They are not distinct things, or at least they were not designed to be. The only reason we chose the more generic term callback was to enable the more uncommon case of making a single call and then getting a single callback.
Our primary goal was to support Webhooks as described here https://webhooks.pbworks.com/w/page/13385128/RESTful%20WebHooks
Having an API that supports Webhook style callbacks but then not providing a way to subscribe to them felt like an edge case to us. I do recognize the need for them in your business, and on reflection, our decision was possibly a bad one.
I wonder if we follow Slack's lead and use the term Events to describe calls that are initiated by a service without prior subscription. I could certainly imagine a top level node called "events" that described one-way interactions. Although, I still find myself asking, but how can a service know where to send events without being able to register a callback URL. How could tooling ever implement the "try" experience without being able to register a callback programmatically? Does Nexmo not provide an API for registering an app? That would be the place where a callback URL is registered.
I think the difference here is that all the webhooks come in to the same URL, so you sort of set it up once when you set your account up, get your API creds, that sort of thing. Then all the events that occur cause a webhook to the URL you specified.
GitHub follow a similar pattern

We do have an API interface for it but it's in a different API (an account/configuration one) so we wouldn't want that endpoint documented here. Users mostly use either a web interface or our CLI tool to configure their endpoint.
Calling it "events" would be entirely fine by me. I think the tendency to have web properties alongside an API with some setup available via the web interface makes it a common pattern to register URLs there since there's an obvious separation between the configuration/setup step and then the actual data flow of API calls and webhooks. I could argue that it's not exactly "correct" to allow this separate setup step but it does seem pretty widely used so I'm keen that OpenAPI might be able to support it (and then I can keep using OpenAPI, yay)
I think creating "events" is a possibility. We should check with AsyncAPI to make sure that we are doing something that is as consistent as possible and try and reduce confusion as we are starting to overlap.
Thoughts from other @OAI/tsc folks?
@lornajane I believe the use case is fairly clear, and so what's missing in the OpenAPI in order to support it. However, there are a couple of things I'd like to discuss:
I have a few comments about the proposal as well, but it's best to keep the discussions separate.
Some good points here @webron
I think one difference between callbacks and webhooks is that since the webhook isn't attached to an operation object, it may be useful to permit a tags field. Any thoughts? I can update the proposal if this seems reasonable.
Hey just wanted to get my $0.02 in somewhere that "callbacks without an endpoint" are super common. whether or not they're the same API or not... meh, like you say its purely philosophical and not particularly relevant to the real world, where people have "an API" and they just added some web hooks to fire off to URLs defined in a interface.
Like Slack:

Like Stripe:

For orgs with a single API it would be really weird to say:
Technically this event being emitted from the application that powers your API is not actually "your API", you need to set up an AsyncAPI description for that. Off you pop!
I'd rather not have to do that. I'd rather just slot the webhooks in next to all the other events and operations for that API, and let them pootle off to AsyncAPI if their architecture expands.
Anyhow, the proposal made it into master so let's close this issue? @darrelmiller
We are implementing it over at stoplight.io for Prism (https://github.com/stoplightio/prism/issues/331) and Docs, so we'll be back with feedback. I recommend other tooling vendors also give implementing it a try and post issues with any issues.
We have it implemented already (as x-webhooks) in our renderer and it works fine (basically it's the same as the callbacks just attached in a new place). See https://developer.nexmo.com/api/sms#inbound-sms
Should this be closed now that PR https://github.com/OAI/OpenAPI-Specification/pull/2103 is merged?
Most helpful comment
Hey just wanted to get my $0.02 in somewhere that "callbacks without an endpoint" are super common. whether or not they're the same API or not... meh, like you say its purely philosophical and not particularly relevant to the real world, where people have "an API" and they just added some web hooks to fire off to URLs defined in a interface.
Like Slack:
Like Stripe:
For orgs with a single API it would be really weird to say:
I'd rather not have to do that. I'd rather just slot the webhooks in next to all the other events and operations for that API, and let them pootle off to AsyncAPI if their architecture expands.