Versioning

The UMA standard provides a method for version negotiation as part of the initial LnurlpRequest. UMA versions include major and minor components in the format <major>.<minor> (eg. 1.2). Minor version bumps are non-breaking, but may contain minor new optional features. Major version bumps include breaking changes. If a VASP only supports versions 1.X, they may not be able to talk to a VASP on version 2.X. The version negotiation flow is as follows:
UMA Version Negotiation
The UMA SDK handles a lot of the heavy lifting for you here. On the receiving VASP side, when trying to parse the LnurlpRequest, you'll get an error if the sending VASP's specified protocol version is incompatible with the SDK version you're using. You can then return a 412 status code.
let umaQuery: uma.LnurlpRequest;
try {
  umaQuery = uma.parseLnurlpRequest(
    new URL(req.url, `${req.protocol}://${req.headers.host}`),
  );
} catch (e) {
  if (e instanceof uma.UnsupportedVersionError) {
    // For unsupported versions, return a 412 "Precondition Failed" as per the spec.
    res.status(412).send({
      supportedMajorVersions: e.supportedMajorVersions,
      unsupportedVersion: e.unsupportedVersion,
    });
    return;
  }
  res.status(400).send('Failed to parse lnurlp request.');
  return;
}
On the sending VASP side, you'll need to look out for a 412 status code response to the LnurlpRequest and then can use the SDK's helpers to retry with an appropriate new version code.
const retryForUnsupportedVersion = async (
  response: globalThis.Response,
  receiver: string,
  request: Request,
) => {
  const responseJson = await response.json();
  const supportedMajorVersions = responseJson.supportedMajorVersions;
  const newSupportedVersion = uma.selectHighestSupportedVersion(
    supportedMajorVersions,
  );
  if (!newSupportedVersion) {
    throw new Error('Failed to find a compatible version.');
  }
  const retryRequest = await uma.getSignedLnurlpRequestUrl({
    isSubjectToTravelRule: true,
    receiverAddress: receiver,
    signingPrivateKey: this.config.umaSigningPrivKey(),
    senderVaspDomain: hostNameWithPort(request),
    umaVersionOverride: newSupportedVersion,
  });
  return fetch(retryRequest);
}
If the sending VASP does not support any of the receiving VASP's protocol versions, the LnurlpRequest fails and the protocol cannot continue.