RocketChat/Rocket.Chat · error · Error

Invalid integration id or token provided.

Error message

Invalid integration id or token provided.

What it means

Thrown by the WebHookAPI authenticatedRoute when no incoming integration matches the integrationId + token pair from the /hooks/:integrationId/:token URL. Integrations.findOneByIdAndToken returns null, meaning either the id does not exist or the token does not match the stored integration token. The token is URL-decoded before lookup.

Source

Thrown at apps/meteor/server/api/webhooks.ts:378

function integrationInfoRest(): { statusCode: number; body: { success: boolean } } {
	incomingLogger.info('Info integration');
	return {
		statusCode: 200,
		body: {
			success: true,
		},
	};
}

class WebHookAPI extends APIClass<'/hooks'> {
	override async authenticatedRoute(routeContext: APIActionContext): Promise<IUser | null> {
		const { integrationId, token } = routeContext.urlParams;
		const integration = await Integrations.findOneByIdAndToken<IIncomingIntegration>(integrationId, decodeURIComponent(token));

		if (!integration) {
			incomingLogger.info({ msg: 'Invalid integration id or token', integrationId, token });

			throw new Error('Invalid integration id or token provided.');
		}

		routeContext.request.headers.set('x-auth-token', token);

		const req = routeContext.request as Request & { integration?: IIncomingIntegration };
		req.integration = integration;

		return Users.findOneById(req.integration.userId);
	}

	override shouldAddRateLimitToRoute(options: { rateLimiterOptions?: RateLimiterOptions | boolean }): boolean {
		const { rateLimiterOptions } = options;
		return (
			(typeof rateLimiterOptions === 'object' || rateLimiterOptions === undefined) &&
			!process.env.TEST_MODE &&
			Boolean(defaultRateLimiterOptions.numRequestsAllowed && defaultRateLimiterOptions.intervalTimeInMS)
		);
	}

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Copy the exact webhook URL from the integration record in admin (Integrations > Incoming > Integration URL) and use it verbatim in the upstream service.
  2. If the token was regenerated, update the upstream webhook URL with the new token.
  3. Confirm the integration still exists and is not deleted; recreate if necessary.
  4. Avoid re-encoding the token; pass it as-is in the path.

Example fix

// before - upstream POSTs to a stale URL
POST /api/v1/hooks/abcOLD/oldToken123

// after - copy current URL from the integration record
POST /api/v1/hooks/<currentId>/<currentToken>
Defensive patterns

Strategy: validation

Validate before calling

const integration = await Integrations.findOneByIdAndToken(id, decodeURIComponent(token));
if (!integration) throw new ClientError('not-found','integration id/token invalid or deleted');

Type guard

function isValidIntegrationRef(id, token) {
  return typeof id === 'string' && id.length>0 && typeof token === 'string' && token.length>0;
}

Try / catch

try { await POST(webhookUrl, body); }
catch (e) {
  if (/Invalid integration id or token/.test(e?.message)) { refreshIntegrationUrl(); return; }
  throw e;
}

Prevention

When it happens

Trigger: POST/GET to /api/v1/hooks/<integrationId>/<token> where integrationId is wrong/deleted, the token is wrong, or the token was URL-encoded incorrectly (e.g. double-encoded). The integration may also have been deleted or its token regenerated.

Common situations: Integration token regenerated in admin but the upstream webhook still has the old URL. Copy-paste of the webhook URL truncated. Token contains characters that were percent-encoded by the client and the server's decodeURIComponent does not reverse them as expected.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12). Data as JSON: /api/errors/573bcd4d62911358. Report an issue: GitHub.