{"record":{"id":"b9472c2f19b46000","repo":"w7corp/easywechat","slug":"missing-v2-api-key","errorCode":null,"errorMessage":"Missing V2 API key.","messagePattern":"Missing V2 API key\\.","errorType":"exception","errorClass":"InvalidConfigException","httpStatus":null,"severity":"error","filePath":"src/Pay/LegacySignature.php","lineNumber":51,"sourceCode":"        $params = $attributes = array_filter(\n            \\array_merge(\n                [\n                    'nonce_str' => $nonce,\n                    'sub_mch_id' => $params['sub_mch_id'] ?? null,\n                    'sub_appid' => $params['sub_appid'] ?? null,\n                ],\n                $params\n            ),\n            static fn ($value, $key) => ! ($key === 'sign' || $value === '' || is_null($value)),\n            ARRAY_FILTER_USE_BOTH\n        );\n\n        ksort($attributes);\n\n        $attributes['key'] = $this->merchant->getV2SecretKey();\n\n        if (empty($attributes['key'])) {\n            throw new InvalidConfigException('Missing V2 API key.');\n        }\n\n        $message = urldecode(http_build_query($attributes));\n\n        if (! empty($params['sign_type']) && $params['sign_type'] === 'HMAC-SHA256') {\n            $sign = hash_hmac('sha256', $message, $attributes['key']);\n        } else {\n            $sign = md5($message);\n        }\n\n        $params['sign'] = strtoupper($sign);\n\n        return $params;\n    }\n}\n","sourceCodeStart":33,"sourceCodeEnd":67,"githubUrl":"https://github.com/w7corp/easywechat/blob/f0cf0a8b8361417ed683b8246d0ecbaf0aafcaa8/src/Pay/LegacySignature.php#L33-L67","documentation":"Thrown by LegacySignature when building a V2 (MD5/HMAC-SHA256) signature and merchant->getV2SecretKey() is empty. The V2 key is a separate 32-character API key from the V3 secretKey; V2 endpoints (transfers, red envelopes, some refunds) cannot be signed without it.","triggerScenarios":"Calling any V2 API through this client or validating a V2 callback signature when Merchant was constructed with v2SecretKey null or ''. E.g. createV2Signature()/ LegacySignature::sign() with only APIv3 secretKey configured.","commonSituations":"New V3-only setup later adding a legacy endpoint (mmpaymkttransfers/*); the V2 key never set on the merchant account; passing the V3 key (43 chars) where the V2 key (32 chars) is expected so it reads as unset; .env variable name typo leaving the value null.","solutions":["Set the 32-char APIv2 key in WeChat Pay merchant console (account center -> API security -> APIv2 key) if not yet set","Pass it as the 5th constructor arg (v2SecretKey) of Merchant, or via your config provider","Verify the value is exactly 32 characters and is the V2 key, not the V3 secretKey"],"exampleFix":"// before\n$merchant = new Merchant($mchId, $privateKey, $cert, $secretKey);\n$app->utils->createV2Signature($params); // throws Missing V2 API key\n// after\n$merchant = new Merchant($mchId, $privateKey, $cert, $secretKey, $v2Key /* 32 chars */);","handlingStrategy":"validation","validationCode":"$v2 = $merchant->getV2SecretKey();\nif ($v2 === null || $v2 === '' || strlen($v2) !== 32) {\n    throw new \\InvalidArgumentException('V2 API key must be set and 32 chars');\n}\n$signature = $app->utils->createV2Signature($params);","typeGuard":"function hasValidV2Key(\\EasyWeChat\\Pay\\Contracts\\Merchant $m): bool\n{\n    $k = $m->getV2SecretKey();\n    return is_string($k) && strlen($k) === 32;\n}","tryCatchPattern":"try {\n    $sign = (new \\EasyWeChat\\Pay\\LegacySignature($merchant))->sign($params);\n} catch (\\EasyWeChat\\Kernel\\Exceptions\\InvalidConfigException $e) {\n    // Missing V2 API key -> configure it, no point retrying\n    throw new \\RuntimeException('Set APIv2 key before calling V2 endpoints', 0, $e);\n}","preventionTips":["Set the APIv2 key in the merchant console before enabling any V2 flow","Keep V2 and V3 keys in separate, clearly named config keys","Unit-test that V2 code paths fail fast at boot when the key is absent"],"tags":["wechat-pay","v2-api-key","legacy-signature","merchant-config"],"backgroundTag":"missing-api-key","analyzedSha":"f0cf0a8b8361417ed683b8246d0ecbaf0aafcaa8","analyzedAt":"2026-08-21T05:29:19.565Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}