bitwarden/server · error · BadRequestException

Invalid Billing Sync Key

Error message

Invalid Billing Sync Key

What it means

Thrown (HTTP 400) by GET /licenses/organization/{id} when the license key matches but _validateBillingSyncKeyCommand.ValidateBillingSyncKeyAsync returns false. The billing sync key is the shared secret that pairs a self-hosted organization with its cloud billing subscription; a mismatch aborts license retrieval.

Source

Thrown at src/Api/Billing/Controllers/LicensesController.cs:85

    /// </summary>
    [HttpGet("organization/{id}")]
    public async Task<OrganizationLicense> OrganizationSync(string id, [FromBody] SelfHostedOrganizationLicenseRequestModel model)
    {
        var organization = await _organizationRepository.GetByIdAsync(new Guid(id));
        if (organization == null)
        {
            throw new NotFoundException("Organization not found.");
        }

        if (!organization.LicenseKey.Equals(model.LicenseKey))
        {
            await Task.Delay(2000);
            throw new BadRequestException("Invalid license key.");
        }

        if (!await _validateBillingSyncKeyCommand.ValidateBillingSyncKeyAsync(organization, model.BillingSyncKey))
        {
            throw new BadRequestException("Invalid Billing Sync Key");
        }

        var license = await _getCloudOrganizationLicenseQuery.GetLicenseAsync(organization, _currentContext.InstallationId.Value);
        return license;
    }
}

View on GitHub (pinned to e93b962371)

Solutions

  1. Regenerate the billing sync key in the cloud organization's billing settings and copy it exactly.
  2. Update the self-hosted billing-sync configuration with the new key.
  3. Verify the key was not truncated or altered during copy.
Defensive patterns

Strategy: validation

Validate before calling

// Verify the billing sync key is configured and well-formed before calling.
if (!billingSyncKey || billingSyncKey.length === 0) {
  throw new Error('Billing sync key is not configured for this organization');
}

Try / catch

try {
  const lic = await getOrgLicense(orgId, body);
} catch (e) {
  if (e.isBadRequest && /invalid billing sync key/i.test(e.message)) {
    await regenerateAndStoreBillingSyncKey(); // then retry once
  } else { throw e; }
}

Prevention

When it happens

Trigger: Wrong or stale billing sync key; the key was regenerated in the cloud portal; the organization was never configured for billing sync.

Common situations: Billing sync key regenerated in cloud org settings but the self-hosted installation still uses the old key; fresh self-hosted install that was never paired.

Related errors


AI-assisted analysis of bitwarden/server@e93b962371 (2026-08-13). Data as JSON: /api/errors/e23ec890d28f4595. Report an issue: GitHub.