@tanakasan1734 you legend, thank you for staying up till 2am working on this!!
Thank you so much for putting this up as a YouTube video as well, really appreciate it! I've converted your JavaScript example into my native Ruby & included it below.
For those still having issues with this API: of significant importance is setting up an "app" in Certificates, Identifiers & Profiles in addition to setting up the "key", so you have an "app ID" registered for WeatherKit in addition to the key being assigned access to it. I would imagine this has something to do with the upcoming billing for WeatherKit.
Full annotated example from my lab notebook:
# WeatherKit REST API: access example
# With thanks to Simon of All The Code (Twitter: @allthecode_)
require 'openssl' # stdlib
require 'logger' # stdlib
require 'http' # gem install http
require 'jwt' # gem install jwt
## APPLE ID's (mine are examples)
TEAM_ID = "TVVX2ENCS3" # Your Apple Developer "team ID", see https://developer.apple.com/account/#!/membership -> "Team ID"
APP_ID = "net.rubynerd.weathervane" # Create an Identifier -> App ID -> App -> set Bundle ID -> App Services -> check WeatherKit -> Save, use Bundle ID here
KEY_ID = "HC2L4UY9UW" # Create a Key -> set Key Name -> check WeatherKit, use Key ID here
KEY_PATH = "/Users/rubynerd/Downloads/AuthKey_HC2L4UY9UW.p8" # Path to file downloaded from key creation above
## GEO VARS
# Charing Cross, nominal centre of London
LAT = "51.5081"
LONG = "0.1248"
TZ = "Europe/London"
DATASETS = %w{currentWeather}.join(",")
# Read the key path to create an ECDSA key
p8 = OpenSSL::PKey::EC.new(File.read(KEY_PATH))
# Create a JWT for accessing WeatherKit
jwt = JWT.encode({
iss: TEAM_ID,
iat: Time.now.to_i,
exp: Time.now.to_i + 3600,
sub: APP_ID,
jti: "#{TEAM_ID}.#{APP_ID}",
}, p8, 'ES256', {
kid: KEY_ID,
id: "#{TEAM_ID}.#{APP_ID}",
})
# Use httprb (https://github.com/httprb/http) to make the request to WeatherKit
res = HTTP.use(logging: {
logger: Logger.new(STDOUT)
}).headers(
"Authorization" => "Bearer #{jwt}",
).get "https://weatherkit.apple.com/api/v1/weather/en/#{LAT}/#{LONG}?dataSets=#{DATASETS}&timezone=#{TZ}"
# Parse the response body from JSON to a Ruby Hash
body = res.parse
# Print the condition code
puts "conditionCode: #{body["currentWeather"]["conditionCode"]}"
# Print required attribution & link
puts "data provided by Apple WeatherKit (#{body["currentWeather"]["metadata"]["attributionURL"]})"
If you're translating the above from Ruby to another language, I've included an expired JWT you can paste into jwt.io's debugger:
eyJraWQiOiJIQzJMNFVZOVVXIiwiaWQiOiJUVlZYMkVOQ1MzLm5ldC5ydWJ5bmVyZC53ZWF0aGVydmFuZSIsImFsZyI6IkVTMjU2In0.eyJpc3MiOiJUVlZYMkVOQ1MzIiwiaWF0IjoxNjU0ODU0NTU5LCJleHAiOjE2NTQ4NTQ1NjQsInN1YiI6Im5ldC5ydWJ5bmVyZC53ZWF0aGVydmFuZSIsImp0aSI6IlRWVlgyRU5DUzMubmV0LnJ1YnluZXJkLndlYXRoZXJ2YW5lIn0.7mGJZvce6D2JmbligmurJc0H4sMa_CwCwHBB4a5yoQvh9n7AljVOpDp7vHblWRG-DPtSqSFzOflM92otKkgQSw
Between the JS and Ruby, this should be enough to close this. I'll leave the feedback request open to push for accurate documentation. Let me know if you have any issues with what's above, or DM me on Twitter if you need further assistance.