### Install dependencies with Bundler Source: https://github.com/eric-guo/wechat/blob/main/GEMINI.md Installs the required gem dependencies using Bundler. Run this in the project root before running tests or linting. ```bash bundle install ``` -------------------------------- ### Enterprise account configuration example Source: https://github.com/eric-guo/wechat/blob/main/README.md Example configuration for a WeChat enterprise account. Must use encrypt mode (enabled by default). The token and encoding_aes_key are obtained from the management console. Includes commented-out multiple account examples. ```yaml default: &default corpid: "corpid" corpsecret: "corpsecret" agentid: 1 access_token: "C:/Users/[user_name]/wechat_access_token" token: "" encoding_aes_key: "" jsapi_ticket: "C:/Users/[user_name]/wechat_jsapi_ticket" production: corpid: <%= ENV['WECHAT_CORPID'] %> corpsecret: <%= ENV['WECHAT_CORPSECRET'] %> agentid: <%= ENV['WECHAT_AGENTID'] %> access_token: <%= ENV['WECHAT_ACCESS_TOKEN'] %> token: <%= ENV['WECHAT_TOKEN'] %> timeout: 30, skip_verify_ssl: true # not recommend encoding_aes_key: <%= ENV['WECHAT_ENCODING_AES_KEY'] %> jsapi_ticket: <%= ENV['WECHAT_JSAPI_TICKET'] %> oauth2_cookie_duration: <%= ENV['WECHAT_OAUTH2_COOKIE_DURATION'] %> development: <<: *default trusted_domain_fullname: "http://your_dev.proxy.qqbrowser.cc" test: <<: *default # Multiple Accounts # # wx2_development: # <<: *default # appid: "my_appid" # secret: "my_secret" # access_token: "tmp/wechat_access_token2" # jsapi_ticket: "tmp/wechat_jsapi_ticket2" # # wx2_test: # <<: *default # appid: "my_appid" # secret: "my_secret" # # wx2_production: # <<: *default # appid: "my_appid" # secret: "my_secret" ``` -------------------------------- ### wechat CLI usage examples Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/cli.md Shows four example invocations of the wechat CLI: querying users, creating a menu from YAML, uploading a CSV batch with a corporate account, and sending a custom text message with a custom token file. Each command includes its expected output or arguments. ```console # public account $ wechat users {"total"=>4, "count"=>4, "data"=>{"openid"=>["oCfEht9***********"]}, "next_openid"=>"..."} ``` ```console # create a menu from YAML $ wechat menu_create config/wechat_menu.yml ``` ```console # corporates: switch account and upload CSV batch $ wechat -a wx2 upload_replaceuser members.csv ``` ```console # custom token file $ wechat -t /tmp/wechat_access_token_2 custom_text oCfEht9oM**** hello ``` -------------------------------- ### Public account configuration example Source: https://github.com/eric-guo/wechat/blob/main/README.md Example configuration for a WeChat public account in config/wechat.yml. Includes default and environment-specific settings with ERB placeholders for production secrets. The development and test environments inherit from the default anchor. ```yaml default: &default appid: "app_id" secret: "app_secret" token: "app_token" access_token: "/var/tmp/wechat_access_token" jsapi_ticket: "/var/tmp/wechat_jsapi_ticket" production: appid: <%= ENV['WECHAT_APPID'] %> secret: <%= ENV['WECHAT_APP_SECRET'] %> token: <%= ENV['WECHAT_TOKEN'] %> access_token: <%= ENV['WECHAT_ACCESS_TOKEN'] %> jsapi_ticket: <%= ENV['WECHAT_JSAPI_TICKET'] %> oauth2_cookie_duration: <%= ENV['WECHAT_OAUTH2_COOKIE_DURATION'] %> # seconds development: <<: *default trusted_domain_fullname: "http://your_dev.proxy.qqbrowser.cc" test: <<: *default ``` -------------------------------- ### Accessing WeChat accounts and configuration Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/configuration.md Demonstrates how to access the default account, a secondary account, and retrieve configuration values. Also shows how to reload the configuration and use environment variables for setup. ```ruby # Rails: config/wechat.yml with default + wx2 accounts Wechat.api # default account Wechat.api(:wx2) # second account Wechat.config(:wx2).timeout # => 20 (default) or configured # reload after DB config changes Wechat.reload_config! # env-only configuration (no config file present) # WECHAT_APPID=... WECHAT_SECRET=... WECHAT_TOKEN=... rails runner 'p Wechat.api.class' ``` -------------------------------- ### Wechat API usage examples Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/api-loader.md Shows three ways to obtain a Wechat API instance: via the module entry point (memoized per account), via the direct factory with overrides, and via manual configuration. Also demonstrates that calling Wechat.config with a missing account raises a RuntimeError with the message "Wechat configuration for missing_account is missing." ```ruby # Factory via module entry point (memoized per account): api = Wechat.api(:wx2) # builds / reuses the instance # Direct factory with overrides: api = Wechat::ApiLoader.with(account: :wx2, token_file: '/tmp/t', type: 'mp', qcloud_env: 'env-id') # Manual configuration for direct construction: cfg = Wechat.config(:default) settings = Wechat::NetworkSetting.new(cfg.timeout, cfg.skip_verify_ssl, cfg.proxy_url, nil, nil) api_config = Wechat::ApiConfig.new(cfg.appid, cfg.secret, cfg.access_token, cfg.jsapi_ticket, settings) api = Wechat::Api.new(api_config) begin Wechat.config(:missing_account) rescue RuntimeError => e puts e.message # => "Wechat configuration for missing_account is missing." end ``` -------------------------------- ### Encrypt and decrypt envelope example Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/signature-cipher.md Shows how to use encrypt, pack, decrypt, and unpack together to encrypt a message and then decrypt it back to the original content and app_id. ```ruby encrypted = Base64.strict_encode64(encrypt(pack(msg, @we_app_id), @we_encoding_aes_key)) content, app_id = unpack(decrypt(Base64.decode64(encrypted), @we_encoding_aes_key)) ``` -------------------------------- ### Per-controller usage with wechat_responder Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/rails-integration.md Example controller using wechat_responder with account selection, token override, and an on handler for text messages. Shows how to configure per-controller options and define message responses. ```ruby class WechatFirstController < ApplicationController wechat_responder account: :new_account, account_from_request: proc { |req| req.params[:wechat] }, token: 'token2', access_token: Rails.root.join('tmp/access_token1') on :text, with: 'help', respond: 'help content' end ``` -------------------------------- ### Mini Program template library management methods Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/mp-api.md Five methods for managing subscribe message templates: browse the public library, get keywords, add a template, list own templates, and delete a template. Each posts JSON to the corresponding WeChat endpoint. ```ruby def list_template_library(offset: 0, count: 20) post 'wxopen/template/library/list', JSON.generate(offset: offset, count: count) end def list_template_library_keywords(id) post 'wxopen/template/library/get', JSON.generate(id: id) end def add_message_template(id, keyword_id_list) post 'wxopen/template/add', JSON.generate(id: id, keyword_id_list: keyword_id_list) end def list_message_template(offset: 0, count: 20) post 'wxopen/template/list', JSON.generate(offset: offset, count: count) end def del_message_template(template_id) post 'wxopen/template/del', JSON.generate(template_id: template_id) end ``` -------------------------------- ### wechat_config_js helper and ERB usage Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/rails-integration.md The Ruby method generates a script tag with wx.config pre-filled with the JS-SDK signature for the current page URL. The ERB example shows how to call it in a view, passing debug and api options, and then use wx.ready to hide the option menu. ```ruby def wechat_config_js(config_options = {}) account = config_options[:account] # ... resolves domain_name / api / app_id (default account vs config[:account]) page_url = ... # trusted_domain_fullname + request.original_fullpath, or original_url; '#...' fragment stripped js_hash = api.jsapi_ticket.signature(page_url) config_js = <<~WECHAT_CONFIG_JS wx.config({ beta: #{config_options[:beta] || false}, debug: #{config_options[:debug] || false}, appId: "#{app_id}", timestamp: "#{js_hash[:timestamp]}", nonceStr: "#{js_hash[:noncestr]}", signature: "#{js_hash[:signature]}", jsApiList: ['#{config_options[:api]&.join("','")}'], openTagList: ['#{config_options[:open_tags]&.join("','")}'] }); WECHAT_CONFIG_JS javascript_tag config_js, type: 'application/javascript' end ``` ```erb
<%= wechat_config_js debug: false, api: %w(hideMenuItems closeWindow) -%> ``` -------------------------------- ### Direct HttpClient usage with NetworkSetting Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/http-client.md Direct use of Wechat::HttpClient with a NetworkSetting, typically not needed since Wechat.api is preferred. Shows GET with params, POST with content_type :json, and rescuing Wechat::ResponseError to print errcode and message. ```ruby settings = Wechat::NetworkSetting.new(20, false, nil, nil, nil) client = Wechat::HttpClient.new('https://api.weixin.qq.com/cgi-bin/', settings) data = client.get 'getcallbackip', params: { access_token: token } # => {"ip_list"=>["101.226.103.0/25", ...]} begin client.post 'message/template/send', body, content_type: :json rescue Wechat::ResponseError => e puts "errcode #{e.error_code}: #{e.message}" end ``` -------------------------------- ### Initialize MpApi constructor Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/mp-api.md Sets up the HTTP client, public access token, JSAPI ticket, and Qcloud token manager for a Mini Program API instance. ```ruby def initialize(api_config, qcloud_setting) super() @client = HttpClient.new(Wechat::Api::API_BASE, api_config.network_setting) @access_token = Token::PublicAccessToken.new(@client, api_config.appid, api_config.secret, api_config.token_file) @jsapi_ticket = Ticket::PublicJsapiTicket.new(@client, @access_token, api_config.jsapi_ticket_file) @qcloud = Qcloud::Token.new(@client, @access_token, qcloud_setting) end ``` -------------------------------- ### Install wechat gem with gem install Source: https://github.com/eric-guo/wechat/blob/main/README.md Install the wechat gem using gem install. For Ruby versions below 2.6, use version 0.12.4. ```bash gem install "wechat" # If your ruby version < 2.6 # gem install wechat -v 0.12.4 ``` -------------------------------- ### Configure for command line (public account) Source: https://github.com/eric-guo/wechat/blob/main/README.md Create a configuration file at ~/.wechat.yml with these contents for a public account. The access_token will be written to /var/tmp/wechat_access_token. ```yaml appid: "my_appid" secret: "my_secret" access_token: "/var/tmp/wechat_access_token" ``` -------------------------------- ### Menu create command Source: https://github.com/eric-guo/wechat/blob/main/README.md Runs `wechat menu_create menu.yaml` to upload the menu defined in the YAML file. Requires management privilege; otherwise, error 60011 is returned. ```shell $ wechat menu_create menu.yaml ``` -------------------------------- ### get Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/http-client.md Performs an HTTP GET request to the specified path. Supports custom headers, query parameters, and response format selection. ```APIDOC ## GET ### Description Performs an HTTP GET request to the specified path. Supports custom headers, query parameters, and response format selection. ### Method GET ### Endpoint {base}{path} ### Parameters #### Path Parameters - **path** (String) - Required - Path appended to `base` (or to `headers[:base]` if given). #### Query Parameters - **params** (Hash) - Optional - Query parameters to include in the request. Passed via `get_header[:params]`. #### Request Headers - **base** (String) - Optional - Override base URL. - **as** (Symbol) - Optional - Response format: `:json`, `:file`, `:xml`, or `:text`. - **Other HTTP headers** (Hash) - Optional - Any additional HTTP headers. ### Request Example ```ruby client.get("/users", { params: { page: 1 }, as: :json }) ``` ### Response #### Success Response (200) - **body** (String) - Response body. #### Response Example ```json { "status": "ok" } ``` ``` -------------------------------- ### get: HTTP GET request with httpx Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/http-client.md Performs an HTTP GET request. The `get_header` hash may include `:base` to override the base URL, `:params` for query parameters, `:as` for response format (`:json`/`:file`/`:xml`/`:text`), and any HTTP headers. The `:params` key is extracted and passed as query parameters. ```ruby def get(path, get_header = {}) request(path, get_header) do |url, headers| params = headers.delete(:params) httpx.with(headers: headers) .get(url, params: params) end end ``` -------------------------------- ### Wechat::HttpClient#initialize Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/http-client.md Creates a new HTTP client instance with the given base URL and network settings, configuring timeouts, proxy, and SSL verification as specified. ```APIDOC ## Wechat::HttpClient#initialize ### Description Initializes a new HTTP client with the provided base URL and network settings, applying timeout, proxy, and SSL verification options. ### Method initialize ### Parameters #### Constructor Parameters - **base** (String) - Required - Base URL prefix; `path` passed to `get`/`post` is appended. One of `ApiBase`'s constants (`API_BASE`, `QYAPI_BASE`, …). - **network_setting** (Wechat::NetworkSetting) - Required - Contains `timeout` (connect + request, seconds), `proxy_url`/`proxy_username`/`proxy_password`, and `skip_verify_ssl`. ### Request Example ```ruby client = Wechat::HttpClient.new(base, network_setting) ``` ### Response #### Success Response - No explicit return value documented; initializes the client instance. #### Response Example ```ruby # No explicit response body ``` ``` -------------------------------- ### show — GET verification handshake Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/responder.md Handles the GET verification handshake. For corp accounts in encrypted mode, decrypts and unpacks the echostr before echoing; for public accounts, echoes the raw echostr. The response is always text/plain. ```ruby def show if @we_corpid.present? echostr, _corp_id = unpack(decrypt(Base64.decode64(params[:echostr]), @we_encoding_aes_key)) render plain: echostr else render plain: params[:echostr] end end ``` -------------------------------- ### batch_job_result Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/corp-api.md Gets the result of a batch job. ```APIDOC ## batch_job_result ### Description Gets the result of a batch job. ### Method POST ### Endpoint Not specified ### Parameters #### Query Parameters - **jobid** (String) - Required - The job ID ### Response #### Success Response Returns the job result. ``` -------------------------------- ### Enable database wechat configurations Source: https://github.com/eric-guo/wechat/blob/main/README.md Generate database configuration migration and run it to create the wechat_configs table for storing multiple wechat accounts. ```console rails g wechat:config rake db:migrate ``` -------------------------------- ### list_template_library_keywords Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/mp-api.md Gets the keywords of a library template. ```APIDOC ## POST wxopen/template/library/get ### Description Gets the keywords of a library template. ### Method POST ### Endpoint wxopen/template/library/get ### Parameters #### Request Body - **id** (String) - Required - The template ID. ### Response #### Success Response (200) - **errcode** (Integer) - Error code, 0 on success. - **errmsg** (String) - Error message. - **keyword_list** (Array) - List of keywords. #### Response Example { "errcode": 0, "errmsg": "ok", "keyword_list": [] } ``` -------------------------------- ### JsapiBase#initialize constructor Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/tokens-tickets.md Initializes a JsapiBase instance with a client, access token, and ticket file path. Sets up a random generator for refresh margin. ```ruby def initialize(client, access_token, jsapi_ticket_file) @client = client @access_token = access_token @jsapi_ticket_file = jsapi_ticket_file @random_generator = Random.new end ``` -------------------------------- ### GET draft/count Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/concerns.md Returns the total number of drafts. ```APIDOC ## GET draft/count ### Description Returns the total number of drafts. ### Method GET ### Endpoint draft/count ### Response #### Success Response (200) - **total_count** (integer) - The total number of drafts. #### Response Example { "total_count": 10 } ``` -------------------------------- ### GET oauth2/auth Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/concerns.md Verifies a web access token. ```APIDOC ## GET oauth2/auth ### Description Verifies a web access token. ### Method GET ### Endpoint oauth2/auth ### Parameters #### Query Parameters - **access_token** (string) - Required - The web access token to verify. - **openid** (string) - Required - The user's OpenID. ### Response #### Success Response (200) - **errcode** (integer) - Error code (0 for success). - **errmsg** (string) - Error message. #### Response Example { "errcode": 0, "errmsg": "ok" } ``` -------------------------------- ### Configure for command line (enterprise account) Source: https://github.com/eric-guo/wechat/blob/main/README.md For enterprise accounts, use 'corpid' instead of 'appid'. The 'corpsecret' must be obtained from the management console. Windows users should store the file at C:/Users/[user_name]/.wechat.yml and use forward slashes in the access_token path. ```yaml corpid: "my_appid" corpsecret: "my_secret" agentid: 1 # Integer, which can be obtained from application settings access_token: "C:/Users/[user_name]/wechat_access_token" ``` -------------------------------- ### batch_replaceuser Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/corp-api.md Starts a batch job to replace users. ```APIDOC ## batch_replaceuser ### Description Starts a batch job to replace users. ### Method POST ### Endpoint Not specified ### Parameters #### Query Parameters - **media_id** (String) - Required - The media ID ### Response #### Success Response Returns a hash with the 'jobid' key. ``` -------------------------------- ### ApiLoader.with - Build API instance Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/api-loader.md Builds the appropriate API instance for an account. Resolves configuration from options or the account config, then selects MpApi, CorpApi, or Api based on type and corpid presence. Raises RuntimeError if credentials or token file cannot be resolved. ```ruby def self.with(options) account = options[:account] || :default c = ApiLoader.config(account) token_file = options[:token_file] || c.access_token.presence || '/var/tmp/wechat_access_token' js_token_file = options[:js_token_file] || c.jsapi_ticket.presence || '/var/tmp/wechat_jsapi_ticket' type = options[:type] || c.type network_setting = Wechat::NetworkSetting.new(c.timeout, c.skip_verify_ssl, c.proxy_url, c.proxy_username, c.proxy_password) current_appid = c.corpid.presence || c.appid current_secret = c.corpsecret.presence || c.secret unless current_appid && current_secret && token_file.present? raise 'Need create ~/.wechat.yml with wechat appid and secret or corpid and corpsecret, or running at rails root folder so wechat can read config/wechat.yml' end api_config = Wechat::ApiConfig.new(current_appid, current_secret, token_file, js_token_file, network_setting) if type == 'mp' qcloud_env = options[:qcloud_env] || c.qcloud_env qcloud_token_file = options[:qcloud_token_file] || c.qcloud_token_file.presence || '/var/tmp/qcloud_access_token' qcloud_token_lifespan = options[:qcloud_token_lifespan] || c.qcloud_token_lifespan qcloud_setting = Wechat::Qcloud::Setting.new(qcloud_env, qcloud_token_file, qcloud_token_lifespan) Wechat::MpApi.new(api_config, qcloud_setting) elsif c.corpid.present? # CorpApi needs agentid Wechat::CorpApi.new(api_config, c.agentid) else # Regular Public Api Wechat::Api.new(api_config) end end ``` -------------------------------- ### GET oauth2/userinfo Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/concerns.md Retrieves the user profile for the `snsapi_userinfo` scope. ```APIDOC ## GET oauth2/userinfo ### Description Retrieves the user profile for the `snsapi_userinfo` scope. ### Method GET ### Endpoint oauth2/userinfo ### Parameters #### Query Parameters - **access_token** (string) - Required - The web access token. - **openid** (string) - Required - The user's OpenID. - **lang** (string) - Optional - Language code, default is `zh_CN`. ### Response #### Success Response (200) - **openid** (string) - The user's OpenID. - **nickname** (string) - The user's nickname. - **sex** (integer) - The user's gender. - **province** (string) - The user's province. - **city** (string) - The user's city. - **country** (string) - The user's country. - **headimgurl** (string) - The user's avatar URL. - **privilege** (array) - The user's privileges. - **unionid** (string) - Optional - The user's union ID. #### Response Example { "openid": "OPENID", "nickname": "NICKNAME", "sex": 1, "province": "PROVINCE", "city": "CITY", "country": "COUNTRY", "headimgurl": "HEADIMGURL", "privilege": [], "unionid": "UNIONID" } ``` -------------------------------- ### Initialize Wechat::HttpClient with timeout, proxy, and SSL settings Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/http-client.md Constructor for Wechat::HttpClient. Configures the HTTPX session with connect and request timeouts from network_setting, optionally adds proxy credentials, and disables SSL verification when skip_verify_ssl is set. The base URL prefix is stored for later use. ```ruby def initialize(base, network_setting) @base = base @httpx = HTTPX.with(timeout: { connect_timeout: network_setting.timeout, request_timeout: network_setting.timeout }) if network_setting.proxy_url.present? @httpx = @httpx.with_proxy(uri: network_setting.proxy_url, username: network_setting.proxy_username, password: network_setting.proxy_password) end return unless network_setting.skip_verify_ssl @httpx = @httpx.with(ssl: { verify_mode: OpenSSL::SSL::VERIFY_NONE }) end ``` -------------------------------- ### GET oauth2/refresh_token Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/concerns.md Refreshes a user's access token. ```APIDOC ## GET oauth2/refresh_token ### Description Refreshes a user's access token. ### Method GET ### Endpoint oauth2/refresh_token ### Parameters #### Query Parameters - **appid** (string) - Required - The application ID. - **grant_type** (string) - Required - Must be `refresh_token`. - **refresh_token** (string) - Required - The refresh token. ### Response #### Success Response (200) - **access_token** (string) - The new access token. - **expires_in** (integer) - Token expiration time in seconds. - **refresh_token** (string) - The new refresh token. - **openid** (string) - The user's OpenID. - **scope** (string) - The scope of the access token. #### Response Example { "access_token": "NEW_ACCESS_TOKEN", "expires_in": 7200, "refresh_token": "NEW_REFRESH_TOKEN", "openid": "OPENID", "scope": "snsapi_userinfo" } ``` -------------------------------- ### Initialize and manage Qcloud token Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/tokens-tickets.md Constructor initializes client, access token, and Qcloud settings. The token method returns the Qcloud token, refreshing it when remaining life is less than a random 30-180 seconds, and retries on AccessTokenExpiredError. The refresh method posts to the TCB endpoint and persists the token. ```ruby def initialize(client, access_token, qcloud_setting) @client = client @access_token = access_token @qcloud_env = qcloud_setting.qcloud_env @qcloud_token_file = qcloud_setting.qcloud_token @qcloud_token_lifespan = qcloud_setting.qcloud_token_lifespan @random_generator = Random.new end def token(tries = 2) read_qcloud_token_from_store refresh if remain_life_seconds < @random_generator.rand(30..(3 * 60)) qcloud_token rescue AccessTokenExpiredError access_token.refresh retry unless (tries -= 1).zero? end def refresh data = client.post('getqcloudtoken', JSON.generate(lifespan: qcloud_token_lifespan), base: ::Wechat::ApiBase::TCB_BASE, params: { access_token: access_token.token }) write_qcloud_token_to_store(data) read_qcloud_token_from_store end ``` -------------------------------- ### GET oauth2/access_token Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/concerns.md Exchanges an authorization code for a web access token. ```APIDOC ## GET oauth2/access_token ### Description Exchanges an authorization code for a web access token. ### Method GET ### Endpoint oauth2/access_token ### Parameters #### Query Parameters - **appid** (string) - Required - The application ID. - **secret** (string) - Required - The application secret. - **code** (string) - Required - The authorization code. - **grant_type** (string) - Required - Must be `authorization_code`. ### Response #### Success Response (200) - **access_token** (string) - The access token. - **expires_in** (integer) - Token expiration time in seconds. - **refresh_token** (string) - The refresh token. - **openid** (string) - The user's OpenID. - **scope** (string) - The scope of the access token. - **unionid** (string) - Optional - The user's union ID. #### Response Example { "access_token": "ACCESS_TOKEN", "expires_in": 7200, "refresh_token": "REFRESH_TOKEN", "openid": "OPENID", "scope": "snsapi_userinfo", "unionid": "UNIONID" } ``` -------------------------------- ### Fetch menu Source: https://github.com/eric-guo/wechat/blob/main/README.md Runs `wechat menu` to retrieve the current menu configuration. The output shows the menu structure with buttons and their types, names, and URLs. ```shell $ wechat menu {"menu"=>{"button"=>[{"type"=>"view", "name"=>"保护的", "url"=>"http://***/protected", "sub_button"=>[]}, {"type"=>"view", "name"=>"公开的", "url"=>"http://***", "sub_button"=>[]}]}} ``` -------------------------------- ### Using wechat_oauth2 in a controller Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/rails-integration.md Example usage of `wechat_oauth2` in a Rails controller. The block receives the openid and can be used to look up the current user. ```ruby class CartController < ApplicationController wechat_api def index wechat_oauth2 do |openid| @current_user = User.find_by(wechat_openid: openid) end end end ``` -------------------------------- ### Wechat::Token::AccessTokenBase#initialize Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/tokens-tickets.md Initializes an access token manager with a client, appid, secret, token file, and optional record storage. ```APIDOC ## Constructor ### Description Creates a new access token manager instance. ### Method initialize ### Parameters - **client** (Wechat::HttpClient) - Required - Transport for the refresh request. - **appid** (String) - Required - Public appid (or corpid for corp). - **secret** (String) - Required - App secret (or corpsecret). - **token_file** (String) - Required - Path to the JSON token store. - **record** (Object with access_token/token_expires_in/got_token_at) - Optional - Record-based storage (e.g. an ActiveRecord row). When present, supersedes token_file. ### Example ```ruby def initialize(client, appid, secret, token_file, record = nil) @appid = appid @secret = secret @client = client @token_file = token_file @record = record @random_generator = Random.new end ``` ``` -------------------------------- ### GET https://open.weixin.qq.com/connect/qrconnect Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/endpoints.md OAuth2 QR login endpoint for WeChat. Used when scope is `snsapi_login` to enable QR code login. ```APIDOC ## GET https://open.weixin.qq.com/connect/qrconnect ### Description OAuth2 QR login endpoint for WeChat. Used when scope is `snsapi_login` to enable QR code login. ### Method GET ### Endpoint https://open.weixin.qq.com/connect/qrconnect ### Parameters #### Query Parameters - **appid** (string) - Required - The application ID. - **redirect_uri** (string) - Required - The redirect URI after authorization. - **scope** (string) - Required - Must be `snsapi_login`. - **response_type** (string) - Required - Must be `code`. - **state** (string) - Required - CSRF state parameter. - **agentid** (string) - Optional - Agent ID for corp accounts. ### Response #### Redirect (302) - **Location** (string) - Redirect URI with `code` and `state` parameters. ``` -------------------------------- ### Generate wechat initializer Source: https://github.com/eric-guo/wechat/blob/main/README.md Run the generator to create the initial wechat.yml configuration file, a sample wechat controller, and corresponding routes. ```console rails generate wechat:install ``` -------------------------------- ### Initialize CorpApi Source: https://github.com/eric-guo/wechat/blob/main/_autodocs/api-reference/corp-api.md The constructor initializes the API client, access token, and JSAPI ticket using the provided configuration and agent ID. ```ruby def initialize(api_config, agentid) super() @client = HttpClient.new(QYAPI_BASE, api_config.network_setting) @access_token = Token::CorpAccessToken.new(@client, api_config.appid, api_config.secret, api_config.token_file) @agentid = agentid @jsapi_ticket = Ticket::CorpJsapiTicket.new(@client, @access_token, api_config.jsapi_ticket_file) @qcloud = nil end ```