shopify_api 14.11.1 → 16.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/api_update_reminder.yml +2 -2
  3. data/.github/workflows/api_update_reminder_on_release.yml +2 -2
  4. data/.github/workflows/build.yml +3 -4
  5. data/.github/workflows/close-waiting-for-response-issues.yml +1 -1
  6. data/.github/workflows/remove-labels-on-activity.yml +1 -1
  7. data/BREAKING_CHANGES_FOR_V15.md +98 -3
  8. data/BREAKING_CHANGES_FOR_V16.md +76 -0
  9. data/CHANGELOG.md +15 -1
  10. data/Gemfile.lock +1 -1
  11. data/RELEASING.md +108 -17
  12. data/REST_RESOURCES.md +161 -0
  13. data/docs/getting_started.md +2 -1
  14. data/docs/usage/oauth.md +129 -0
  15. data/docs/usage/webhooks.md +0 -17
  16. data/lib/shopify_api/admin_versions.rb +1 -5
  17. data/lib/shopify_api/auth/oauth/access_token_response.rb +5 -1
  18. data/lib/shopify_api/auth/oauth.rb +7 -2
  19. data/lib/shopify_api/auth/refresh_token.rb +57 -0
  20. data/lib/shopify_api/auth/session.rb +36 -19
  21. data/lib/shopify_api/auth/token_exchange.rb +50 -0
  22. data/lib/shopify_api/clients/graphql/storefront.rb +5 -11
  23. data/lib/shopify_api/clients/http_client.rb +2 -0
  24. data/lib/shopify_api/context.rb +12 -5
  25. data/lib/shopify_api/rest/resources/2025_10/abandoned_checkout.rb +194 -0
  26. data/lib/shopify_api/rest/resources/2025_10/access_scope.rb +62 -0
  27. data/lib/shopify_api/rest/resources/2025_10/apple_pay_certificate.rb +109 -0
  28. data/lib/shopify_api/rest/resources/2025_10/application_charge.rb +113 -0
  29. data/lib/shopify_api/rest/resources/2025_10/application_credit.rb +95 -0
  30. data/lib/shopify_api/rest/resources/2025_10/article.rb +269 -0
  31. data/lib/shopify_api/rest/resources/2025_10/asset.rb +122 -0
  32. data/lib/shopify_api/rest/resources/2025_10/assigned_fulfillment_order.rb +92 -0
  33. data/lib/shopify_api/rest/resources/2025_10/balance.rb +58 -0
  34. data/lib/shopify_api/rest/resources/2025_10/blog.rb +166 -0
  35. data/lib/shopify_api/rest/resources/2025_10/cancellation_request.rb +87 -0
  36. data/lib/shopify_api/rest/resources/2025_10/carrier_service.rb +120 -0
  37. data/lib/shopify_api/rest/resources/2025_10/checkout.rb +213 -0
  38. data/lib/shopify_api/rest/resources/2025_10/collect.rb +146 -0
  39. data/lib/shopify_api/rest/resources/2025_10/collection.rb +114 -0
  40. data/lib/shopify_api/rest/resources/2025_10/collection_listing.rb +159 -0
  41. data/lib/shopify_api/rest/resources/2025_10/comment.rb +287 -0
  42. data/lib/shopify_api/rest/resources/2025_10/country.rb +141 -0
  43. data/lib/shopify_api/rest/resources/2025_10/currency.rb +61 -0
  44. data/lib/shopify_api/rest/resources/2025_10/custom_collection.rb +191 -0
  45. data/lib/shopify_api/rest/resources/2025_10/customer.rb +328 -0
  46. data/lib/shopify_api/rest/resources/2025_10/deprecated_api_call.rb +61 -0
  47. data/lib/shopify_api/rest/resources/2025_10/discount_code.rb +226 -0
  48. data/lib/shopify_api/rest/resources/2025_10/dispute.rb +115 -0
  49. data/lib/shopify_api/rest/resources/2025_10/dispute_evidence.rb +121 -0
  50. data/lib/shopify_api/rest/resources/2025_10/dispute_file_upload.rb +85 -0
  51. data/lib/shopify_api/rest/resources/2025_10/draft_order.rb +279 -0
  52. data/lib/shopify_api/rest/resources/2025_10/event.rb +152 -0
  53. data/lib/shopify_api/rest/resources/2025_10/fulfillment.rb +235 -0
  54. data/lib/shopify_api/rest/resources/2025_10/fulfillment_event.rb +167 -0
  55. data/lib/shopify_api/rest/resources/2025_10/fulfillment_order.rb +326 -0
  56. data/lib/shopify_api/rest/resources/2025_10/fulfillment_request.rb +116 -0
  57. data/lib/shopify_api/rest/resources/2025_10/fulfillment_service.rb +134 -0
  58. data/lib/shopify_api/rest/resources/2025_10/gift_card.rb +222 -0
  59. data/lib/shopify_api/rest/resources/2025_10/gift_card_adjustment.rb +122 -0
  60. data/lib/shopify_api/rest/resources/2025_10/image.rb +161 -0
  61. data/lib/shopify_api/rest/resources/2025_10/inventory_item.rb +112 -0
  62. data/lib/shopify_api/rest/resources/2025_10/inventory_level.rb +183 -0
  63. data/lib/shopify_api/rest/resources/2025_10/location.rb +171 -0
  64. data/lib/shopify_api/rest/resources/2025_10/locations_for_move.rb +60 -0
  65. data/lib/shopify_api/rest/resources/2025_10/marketing_event.rb +213 -0
  66. data/lib/shopify_api/rest/resources/2025_10/metafield.rb +348 -0
  67. data/lib/shopify_api/rest/resources/2025_10/mobile_platform_application.rb +120 -0
  68. data/lib/shopify_api/rest/resources/2025_10/order.rb +503 -0
  69. data/lib/shopify_api/rest/resources/2025_10/order_risk.rb +148 -0
  70. data/lib/shopify_api/rest/resources/2025_10/page.rb +198 -0
  71. data/lib/shopify_api/rest/resources/2025_10/payment.rb +98 -0
  72. data/lib/shopify_api/rest/resources/2025_10/payment_gateway.rb +147 -0
  73. data/lib/shopify_api/rest/resources/2025_10/payment_transaction.rb +117 -0
  74. data/lib/shopify_api/rest/resources/2025_10/payout.rb +101 -0
  75. data/lib/shopify_api/rest/resources/2025_10/policy.rb +73 -0
  76. data/lib/shopify_api/rest/resources/2025_10/price_rule.rb +227 -0
  77. data/lib/shopify_api/rest/resources/2025_10/product.rb +227 -0
  78. data/lib/shopify_api/rest/resources/2025_10/product_listing.rb +200 -0
  79. data/lib/shopify_api/rest/resources/2025_10/product_resource_feedback.rb +92 -0
  80. data/lib/shopify_api/rest/resources/2025_10/province.rb +136 -0
  81. data/lib/shopify_api/rest/resources/2025_10/recurring_application_charge.rb +184 -0
  82. data/lib/shopify_api/rest/resources/2025_10/redirect.rb +143 -0
  83. data/lib/shopify_api/rest/resources/2025_10/refund.rb +158 -0
  84. data/lib/shopify_api/rest/resources/2025_10/resource_feedback.rb +77 -0
  85. data/lib/shopify_api/rest/resources/2025_10/script_tag.rb +159 -0
  86. data/lib/shopify_api/rest/resources/2025_10/shipping_zone.rb +87 -0
  87. data/lib/shopify_api/rest/resources/2025_10/shop.rb +231 -0
  88. data/lib/shopify_api/rest/resources/2025_10/smart_collection.rb +220 -0
  89. data/lib/shopify_api/rest/resources/2025_10/storefront_access_token.rb +91 -0
  90. data/lib/shopify_api/rest/resources/2025_10/tender_transaction.rb +97 -0
  91. data/lib/shopify_api/rest/resources/2025_10/theme.rb +127 -0
  92. data/lib/shopify_api/rest/resources/2025_10/transaction.rb +194 -0
  93. data/lib/shopify_api/rest/resources/2025_10/usage_charge.rb +106 -0
  94. data/lib/shopify_api/rest/resources/2025_10/user.rb +142 -0
  95. data/lib/shopify_api/rest/resources/2025_10/variant.rb +212 -0
  96. data/lib/shopify_api/rest/resources/2025_10/webhook.rb +173 -0
  97. data/lib/shopify_api/version.rb +1 -1
  98. data/lib/shopify_api/webhooks/registration.rb +3 -3
  99. data/lib/shopify_api/webhooks/registry.rb +3 -13
  100. data/lib/shopify_api/webhooks/{handler.rb → webhook_handler.rb} +0 -12
  101. data/lib/shopify_api.rb +1 -1
  102. data/shopify_api.gemspec +1 -1
  103. metadata +79 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a74f8e8dd48cdc2900573e00f7dc6bb4ba302608075c7b06c285ee5dab6ca8ed
4
- data.tar.gz: e7cf3797171b79502f913bb289b518f349841de3adc1f576753f403732f7ea1f
3
+ metadata.gz: fcfda3eae9679802b0a7d174700dfbd87d43f31f2a06a94369f5466c52da9c25
4
+ data.tar.gz: cd43a51872ca579701c3592603c9a41b9662191a62420fdbe87e26cd71020e3f
5
5
  SHA512:
6
- metadata.gz: 45a9b83fddf9151bc99ba13e3353a8ac42cbf6559442cc6133f2c587670f1bbb1638ab5e40d8a799d412fb6d6943acc0ca60e99838480f45292f2951cb2de67f
7
- data.tar.gz: 7ce124fc5e459a17c2230efc2577ace84922db124a7d79f3cf59693664507b319077558bd7a20146d2f0848c6eeb689eba535c3614e8443b546d3fa8583f75cf
6
+ metadata.gz: 33c6187ea237123c293e5597e184f633ddcfedb7433f7d3ad14141fb4b401cd618264f2fe3143982141b03ba7ee00aad7ec08b26a0b489b6c00b836edc61a8ec
7
+ data.tar.gz: 251fea50aaa98a67b55797934744bd9a57599084740530535dd6c98d9a8f1f2f886617d3dd66a99c7f877c508ac2afbcf3cf18a52758dfb9b2262c0314d06c8e
@@ -8,8 +8,8 @@ jobs:
8
8
  reminder:
9
9
  runs-on: ubuntu-latest
10
10
  steps:
11
- - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
12
- - uses: JasonEtco/create-an-issue@e6b4b190af80961b6462c725454e7828d0247a68 # v2.4.0
11
+ - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
12
+ - uses: JasonEtco/create-an-issue@1b14a70e4d8dc185e5cc76d3bec9eab20257b2c5 # v2.9.2
13
13
  env:
14
14
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
15
15
  with:
@@ -8,8 +8,8 @@ jobs:
8
8
  reminder:
9
9
  runs-on: ubuntu-latest
10
10
  steps:
11
- - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
12
- - uses: JasonEtco/create-an-issue@e6b4b190af80961b6462c725454e7828d0247a68 # v2.4.0
11
+ - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
12
+ - uses: JasonEtco/create-an-issue@1b14a70e4d8dc185e5cc76d3bec9eab20257b2c5 # v2.9.2
13
13
  env:
14
14
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
15
15
  with:
@@ -11,14 +11,13 @@ jobs:
11
11
  strategy:
12
12
  matrix:
13
13
  version:
14
- - 3.0
15
- - 3.1
16
14
  - 3.2
17
15
  - 3.3
16
+ - 3.4
18
17
  steps:
19
- - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
18
+ - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
20
19
  - name: Set up Ruby ${{ matrix.version }}
21
- uses: ruby/setup-ruby@e34163cd15f4bb403dcd72d98e295997e6a55798 # v1.238.0
20
+ uses: ruby/setup-ruby@829114fc20da43a41d27359103ec7a63020954d4 # v1.255.0
22
21
  with:
23
22
  ruby-version: ${{ matrix.version }}
24
23
  - name: Install OpenSSL
@@ -8,7 +8,7 @@ jobs:
8
8
  runs-on: ubuntu-latest
9
9
  steps:
10
10
  - name: close-issues
11
- uses: actions-cool/issues-helper@a610082f8ac0cf03e357eb8dd0d5e2ba075e017e # v3.6.0
11
+ uses: actions-cool/issues-helper@45d75b6cf72bf4f254be6230cb887ad002702491 # v3.6.3
12
12
  with:
13
13
  actions: 'close-issues'
14
14
  token: ${{ secrets.GITHUB_TOKEN }}
@@ -7,7 +7,7 @@ jobs:
7
7
  remove-labels-on-activity:
8
8
  runs-on: ubuntu-latest
9
9
  steps:
10
- - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
10
+ - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
11
11
  - uses: actions-ecosystem/action-remove-labels@2ce5d41b4b6aa8503e285553f75ed56e0a40bae0 # v1.2.0
12
12
  if: contains(github.event.issue.labels.*.name, 'Waiting for Response')
13
13
  with:
@@ -1,5 +1,99 @@
1
1
  # Breaking change notice for version 15.0.0
2
2
 
3
+ ## Removal of positional `storefront_access_token` parameter from Storefront GraphQL Client
4
+
5
+ The `ShopifyAPI::Clients::Graphql::Storefront` class no longer accepts the public Storefront access token as a positional parameter. You must now use the named parameters `private_token:` or `public_token:` instead.
6
+
7
+ This parameter was deprecated in [PR #1302](https://github.com/Shopify/shopify-api-ruby/pull/1302) (v14.1.0).
8
+
9
+ ### Previous implementation (deprecated in v14.1.0)
10
+
11
+ ```ruby
12
+ # Old way: passing token as positional parameter
13
+ client = ShopifyAPI::Clients::Graphql::Storefront.new(shop_url, storefront_access_token)
14
+
15
+ # With API version
16
+ client = ShopifyAPI::Clients::Graphql::Storefront.new(shop_url, storefront_access_token, api_version: "2024-01")
17
+ ```
18
+
19
+ ### New implementation (required in v15.0.0)
20
+
21
+ ```ruby
22
+ # Use private token (recommended)
23
+ client = ShopifyAPI::Clients::Graphql::Storefront.new(shop_url, private_token: storefront_private_access_token)
24
+
25
+ # Or use public token
26
+ client = ShopifyAPI::Clients::Graphql::Storefront.new(shop_url, public_token: storefront_public_access_token)
27
+
28
+ # With API version
29
+ client = ShopifyAPI::Clients::Graphql::Storefront.new(
30
+ shop_url,
31
+ private_token: storefront_private_access_token,
32
+ api_version: "2024-01"
33
+ )
34
+ ```
35
+
36
+ For more information on private vs public Storefront access tokens, see [Shopify's authentication documentation](https://shopify.dev/docs/api/usage/authentication#getting-started-with-private-access).
37
+ ## Removal of `LATEST_SUPPORTED_ADMIN_VERSION` and `RELEASE_CANDIDATE_ADMIN_VERSION` constants
38
+
39
+ The `LATEST_SUPPORTED_ADMIN_VERSION` and `RELEASE_CANDIDATE_ADMIN_VERSION` constants have been removed to prevent semantic versioning (semver) breaking changes. Previously, these constants would automatically update every quarter when new API versions were released, causing unintended breaking changes for apps.
40
+
41
+ ### Migration Guide
42
+
43
+ **If you were using these constants directly:**
44
+
45
+ ```ruby
46
+ # Before (v14 and earlier)
47
+ api_version = ShopifyAPI::LATEST_SUPPORTED_ADMIN_VERSION
48
+ # or
49
+ api_version = ShopifyAPI::RELEASE_CANDIDATE_ADMIN_VERSION
50
+
51
+ # After (v15+)
52
+ api_version = "2025-07" # Explicitly specify the version you want to use
53
+ ```
54
+
55
+ **In your Context.setup:**
56
+
57
+ The `api_version` parameter has always been required in `Context.setup`, so most apps should not be affected. However, you must now explicitly specify which API version you want to use:
58
+
59
+ ```ruby
60
+ # Before (v14 and earlier)
61
+ ShopifyAPI::Context.setup(
62
+ api_key: "<api-key>",
63
+ api_secret_key: "<api-secret-key>",
64
+ host: "<https://application-host-name.com>",
65
+ scope: "read_orders,read_products,etc",
66
+ is_embedded: true,
67
+ api_version: ShopifyAPI::LATEST_SUPPORTED_ADMIN_VERSION, # This constant no longer exists
68
+ is_private: false,
69
+ )
70
+
71
+ # After (v15+)
72
+ ShopifyAPI::Context.setup(
73
+ api_key: "<api-key>",
74
+ api_secret_key: "<api-secret-key>",
75
+ host: "<https://application-host-name.com>",
76
+ scope: "read_orders,read_products,etc",
77
+ is_embedded: true,
78
+ api_version: "2025-07", # Explicitly specify the version
79
+ is_private: false,
80
+ )
81
+ ```
82
+
83
+ **Finding the right API version:**
84
+
85
+ You can see all supported API versions by referencing:
86
+ ```ruby
87
+ ShopifyAPI::SUPPORTED_ADMIN_VERSIONS
88
+ # => ["unstable", "2025-10", "2025-07", "2025-04", ...]
89
+ ```
90
+
91
+ **Why this change?**
92
+ By requiring explicit version specification, apps can:
93
+ - Control when they upgrade to new API versions
94
+ - Test thoroughly before upgrading
95
+ - Avoid unexpected breaking changes from automatic version updates
96
+
3
97
  ## Removal of `ShopifyAPI::Webhooks::Handler`
4
98
 
5
99
  The `ShopifyAPI::Webhooks::Handler` class has been removed in favor of `ShopifyAPI::Webhooks::WebhookHandler`. The `ShopifyAPI::Webhooks::WebhookHandler` class is now the recommended way to handle webhooks.
@@ -8,7 +102,8 @@ Make a module or class that includes or extends `ShopifyAPI::Webhooks::WebhookHa
8
102
 
9
103
  In v14, adding new fields to the callback would become a breaking change. To make this code more flexible, handlers will now receive an object that can be typed and extended.
10
104
 
11
- `data` will have the following keys
105
+ `data` will have the following keys:
106
+
12
107
  - `topic`, `String` - The topic of the webhook
13
108
  - `shop`, `String` - The shop domain of the webhook
14
109
  - `body`, `T::Hash[String, T.untyped]`- The body of the webhook
@@ -21,8 +116,8 @@ module WebhookHandler
21
116
  extend ShopifyAPI::Webhooks::WebhookHandler
22
117
 
23
118
  class << self
24
- def handle_webhook(data:)
25
- puts "Received webhook! topic: #{data.topic} shop: #{data.shop} body: #{data.body} webhook_id: #{data.webhook_id} api_version: #{data.api_version"
119
+ def handle(data:)
120
+ puts "Received webhook! topic: #{data.topic} shop: #{data.shop} body: #{data.body} webhook_id: #{data.webhook_id} api_version: #{data.api_version}"
26
121
  end
27
122
  end
28
123
  end
@@ -0,0 +1,76 @@
1
+ # Breaking change notice for version 16.0.0
2
+
3
+ ## Minimum Ruby Version Requirement
4
+
5
+ The minimum required Ruby version has been updated from 3.0 to 3.2.
6
+
7
+ ### Why this change?
8
+
9
+ Ruby 3.0 and 3.1 have reached End of Life (EOL).
10
+
11
+ ### Migration Guide
12
+
13
+ If you're currently using Ruby 3.0 or 3.1, you'll need to upgrade to Ruby 3.2 or higher before upgrading to shopify-api-ruby v16.0.0.
14
+
15
+ **Note:** Ruby 3.2+ includes performance improvements and new features. Most applications should not require code changes beyond updating the Ruby version itself.
16
+ ## Removal of `Session#serialize` and `Session.deserialize` methods
17
+
18
+ The `Session#serialize` and `Session.deserialize` methods have been removed due to a security vulnerability. The `deserialize` method used `Oj.load` without safe mode, which allows instantiation of arbitrary Ruby objects.
19
+
20
+ These methods were originally created for session persistence when the library handled session storage. After session storage was deprecated in v12.3.0, applications became responsible for their own session persistence, making these methods unnecessary for their original purpose.
21
+
22
+ ### Why this change?
23
+
24
+ **No impact on most applications:** The `shopify_app gem` stores individual session attributes in database columns and reconstructs sessions using `Session.new()`, which is the recommended pattern.
25
+
26
+ ## Migration Guide
27
+
28
+ If your application was using `Session#serialize` and `Session.deserialize` for session persistence, you'll need to refactor to store individual session attributes and reconstruct sessions using `Session.new()`.
29
+
30
+ ### Previous implementation (removed in v16.0.0)
31
+
32
+ ```ruby
33
+ # Storing a session
34
+ session = ShopifyAPI::Auth::Session.new(
35
+ shop: "example.myshopify.com",
36
+ access_token: "shpat_xxxxx",
37
+ scope: "read_products,write_orders"
38
+ )
39
+
40
+ serialized_data = session.serialize
41
+ # Store serialized_data in Redis, database, etc.
42
+ redis.set("session:#{session.id}", serialized_data)
43
+
44
+ # Retrieving a session
45
+ serialized_data = redis.get("session:#{session_id}")
46
+ session = ShopifyAPI::Auth::Session.deserialize(serialized_data)
47
+ ```
48
+
49
+ ### New implementation (required in v16.0.0)
50
+
51
+ Store individual session attributes and reconstruct using `Session.new()`:
52
+
53
+ ## Reference: shopify_app gem implementation
54
+
55
+ The [shopify_app gem](https://github.com/Shopify/shopify_app) provides a reference implementation of session storage that follows these best practices:
56
+
57
+ **Shop Session Storage** ([source](https://github.com/Shopify/shopify_app/blob/main/lib/shopify_app/session/shop_session_storage.rb)):
58
+ ```ruby
59
+ # Stores attributes in database columns
60
+ def store(auth_session)
61
+ shop = find_or_initialize_by(shopify_domain: auth_session.shop)
62
+ shop.shopify_token = auth_session.access_token
63
+ shop.save!
64
+ end
65
+
66
+ # Reconstructs using Session.new()
67
+ def retrieve(id)
68
+ shop = find_by(id: id)
69
+ return unless shop
70
+
71
+ ShopifyAPI::Auth::Session.new(
72
+ shop: shop.shopify_domain,
73
+ access_token: shop.shopify_token
74
+ )
75
+ end
76
+ ```
data/CHANGELOG.md CHANGED
@@ -1,7 +1,21 @@
1
1
  # Changelog
2
2
 
3
3
  Note: For changes to the API, see https://shopify.dev/changelog?filter=api
4
- ## Unreleased
4
+ ## 16.0.0 (2025-12-10)
5
+ - ⚠️ [Breaking] Minimum required Ruby version is now 3.2. Ruby 3.0 and 3.1 are no longer supported.
6
+ - ⚠️ [Breaking] Removed `Session#serialize` and `Session.deserialize` methods due to security concerns (RCE vulnerability via `Oj.load`). These methods were not used internally by the library. If your application relies on session serialization, use `Session.new()` to reconstruct sessions from stored attributes instead.
7
+
8
+ - Add support for expiring offline access tokens with refresh tokens. See [OAuth documentation](docs/usage/oauth.md#expiring-offline-access-tokens) for details.
9
+ - Add `ShopifyAPI::Auth::TokenExchange.migrate_to_expiring_token` method to migrate existing non-expiring offline tokens to expiring tokens. See [migration documentation](docs/usage/oauth.md#migrating-non-expiring-tokens-to-expiring-tokens) for details.
10
+
11
+ ### 15.0.0
12
+
13
+ - ⚠️ [Breaking] Removed deprecated `ShopifyAPI::Webhooks::Handler` interface. Apps must migrate to `ShopifyAPI::Webhooks::WebhookHandler` which provides `webhook_id` and `api_version` in addition to `topic`, `shop`, and `body`. See [BREAKING_CHANGES_FOR_V15.md](BREAKING_CHANGES_FOR_V15.md) for migration guide.
14
+ - Add support for 2025-10 API version
15
+ - Updated `LATEST_SUPPORTED_ADMIN_VERSION` to `2025-10`
16
+ - [#1411](https://github.com/Shopify/shopify-api-ruby/pull/1411) Remove `LATEST_SUPPORTED_ADMIN_VERSION` and `RELEASE_CANDIDATE_ADMIN_VERSION` constants to prevent semver violations. Developers must now explicitly specify API versions. See the [migration guide](BREAKING_CHANGES_FOR_V15.md#removal-of-latest_supported_admin_version-and-release_candidate_admin_version-constants) for details.
17
+
18
+ - [#1405](https://github.com/Shopify/shopify-api-ruby/pull/1405) Fix webhook registration for topics containing dots (e.g., `customer.tags_added`, `customer.tags_removed`)
5
19
 
6
20
  ## 14.11.1
7
21
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- shopify_api (14.11.1)
4
+ shopify_api (16.0.0)
5
5
  activesupport
6
6
  concurrent-ruby
7
7
  hash_diff
data/RELEASING.md CHANGED
@@ -1,19 +1,110 @@
1
1
  # Releasing ShopifyAPI
2
2
 
3
- 1. Before releasing, make sure `sorbet` and related gems are up to date:
4
- `bundle update sorbet sorbet-runtime sorbet-static tapioca --conservative`
5
- 1. Check the Semantic Versioning page for info on how to version the new release: http://semver.org
6
- 1. Update the version of ShopifyAPI in lib/shopify_api/version.rb
7
- 1. Run `bundle`
8
- 1. Add a CHANGELOG entry for the new release
9
- 1. Commit the changes with a commit message like "Packaging for release X.Y.Z"
10
- 1. Tag the release with the version (Leave REV blank for HEAD or provide a SHA)
11
- $ git tag vX.Y.Z REV
12
- 1. Push out the changes
13
- $ git push
14
- 1. Push out the tags
15
- $ git push --tags
16
- 1. Publish the gem using Shipit
17
- 1. Consider if the dependency in Shopify/shopify needs updated. It's used only by the tests so is a low risk change.
18
- Also consider Shopify/shopify_app whose gemspec depends on this.
19
- We don't need to do this for every release, but we should try to keep them relatively up to date.
3
+ ## Prerequisites
4
+
5
+ Before starting a release, ensure you have:
6
+
7
+ - Merged all code change PRs into main
8
+
9
+ ## Release Process
10
+
11
+ ### Step 1: Prepare the Release Branch
12
+
13
+ 1. **Ensure all feature changes are merged**
14
+
15
+ ```bash
16
+ git checkout main
17
+ git pull origin main
18
+ ```
19
+
20
+ Verify: Latest commits should match GitHub's main branch.
21
+
22
+ 2. **Review changes to determine version bump**
23
+ - Review merged PRs since last release: `git log v14.11.1..HEAD --oneline`
24
+ - Apply [semantic versioning](https://semver.org/):
25
+ - PATCH (X.Y.Z+1): Bug fixes only
26
+ - MINOR (X.Y+1.0): New features, backward compatible
27
+ - MAJOR (X+1.0.0): Breaking changes
28
+
29
+ ### Step 2: Create Release Pull Request
30
+
31
+ 1. **Create a new branch**
32
+
33
+ ```bash
34
+ git checkout -b vX.Y.Z
35
+ ```
36
+
37
+ 2. **Update version number**
38
+ Edit `lib/shopify_api/version.rb`:
39
+
40
+ ```ruby
41
+ module ShopifyAPI
42
+ VERSION = "X.Y.Z" # Replace with your version
43
+ end
44
+ ```
45
+
46
+ 3. **Update dependencies**
47
+
48
+ ```bash
49
+ bundle update sorbet sorbet-runtime sorbet-static tapioca --conservative
50
+ bundle install
51
+ ```
52
+
53
+ Expected: Gemfile.lock updates with new dependency versions.
54
+
55
+ 4. **Update CHANGELOG**
56
+ - Add entry under "## Unreleased" with format:
57
+
58
+ ```markdown
59
+ ## X.Y.Z (YYYY-MM-DD)
60
+
61
+ - [#PR_NUMBER](https://github.com/Shopify/shopify-api-ruby/pull/PR_NUMBER) Description of change
62
+ ```
63
+
64
+ - Move all unreleased items under the new version
65
+
66
+ 5. **Create and push PR**
67
+
68
+ ```bash
69
+ git add -A
70
+ git commit -m "preparing for release v X.Y.Z"
71
+ git push origin release-X.Y.Z
72
+ ```
73
+
74
+ - Title PR: "Release vX.Y.Z"
75
+ - Add release notes to PR description
76
+
77
+ ### Step 3: Tag and Publish
78
+
79
+ 1. **After PR is merged, update local main**
80
+
81
+ ```bash
82
+ git checkout main
83
+ git pull origin main
84
+ ```
85
+
86
+ Verify: `git log -1` shows your merge commit.
87
+
88
+ 2. **Create and push tag**
89
+
90
+ ```bash
91
+ git tag -f vX.Y.Z && git push origin vX.Y.Z
92
+ ```
93
+
94
+ Verify: Tag appears at [https://github.com/Shopify/shopify-api-ruby/tags](https://github.com/Shopify/shopify-api-ruby/tags)
95
+
96
+ 3. **Publish via Shipit**
97
+
98
+ 4. **Verify gem publication**
99
+
100
+ List the gem on [https://rubygems.org/gems/shopify_api](https://rubygems.org/gems/shopify_api/versions/)
101
+
102
+ Expected: Shows your new version (may take 5-10 minutes).
103
+
104
+ ### Step 4: Update Dependent Projects (Optional)
105
+
106
+ For major/minor releases, update these repositories:
107
+
108
+ - **Shopify/shopify_app**: Update gemspec
109
+ - File: `shopify_app.gemspec`
110
+ - Priority: High for breaking changes, medium otherwise
data/REST_RESOURCES.md ADDED
@@ -0,0 +1,161 @@
1
+ # Adding a New API Version to Shopify API Ruby
2
+
3
+ ## Overview
4
+ This guide provides step-by-step instructions for adding a new API version to the Shopify API Ruby library. This example uses the addition of the 2025-07 API version as a reference, but the process applies to any new API version.
5
+
6
+ ## Prerequisites
7
+ - Understanding of any breaking changes or removed resources in the new API version
8
+
9
+ ## Step 1: Update API Version Constants
10
+
11
+ ### Update admin_versions.rb
12
+ Edit `lib/shopify_api/admin_versions.rb` to add your new version:
13
+
14
+ ```ruby
15
+ module ShopifyAPI
16
+ module AdminVersions
17
+ SUPPORTED_ADMIN_VERSIONS = T.let([
18
+ "unstable",
19
+ "2025-10", # Add new version here
20
+ "2025-07",
21
+ "2025-04",
22
+ # ... other versions
23
+ ], T::Array[String])
24
+
25
+ LATEST_SUPPORTED_ADMIN_VERSION = T.let("2025-07", String) # Update if this is the latest stable
26
+ RELEASE_CANDIDATE_ADMIN_VERSION = T.let("2025-10", String) # Update if this is RC
27
+ end
28
+ end
29
+ ```
30
+
31
+ **Version Management:**
32
+ - Add new versions to the top of `SUPPORTED_ADMIN_VERSIONS`
33
+ - Update `LATEST_SUPPORTED_ADMIN_VERSION` when the version is stable
34
+ - Update `RELEASE_CANDIDATE_ADMIN_VERSION` for release candidates
35
+
36
+ ## Step 2: Create Directory Structure
37
+
38
+ ### Create Resource Directory
39
+ ```bash
40
+ mkdir lib/shopify_api/rest/resources/{YYYY_MM}/
41
+ ```
42
+ Example: `lib/shopify_api/rest/resources/2025_07/`
43
+
44
+ ### Create Test Directory
45
+ ```bash
46
+ mkdir test/rest/{YYYY_MM}/
47
+ ```
48
+ Example: `test/rest/2025_07/`
49
+
50
+ **Directory Naming Convention:**
51
+ - Format: `YYYY_MM` (e.g., `2025_04`, `2025_07`, `2025_10`)
52
+ - Use underscore between year and month
53
+
54
+ ## Step 3: Copy Resource Files from Previous Version
55
+
56
+ ### Copy All Resource Files
57
+ ```bash
58
+ # Copy resource files
59
+ cp -r lib/shopify_api/rest/resources/{PREVIOUS_VERSION}/* lib/shopify_api/rest/resources/{NEW_VERSION}/
60
+
61
+ # Copy test files
62
+ cp -r test/rest/{PREVIOUS_VERSION}/* test/rest/{NEW_VERSION}/
63
+ ```
64
+
65
+ Example:
66
+ ```bash
67
+ cp -r lib/shopify_api/rest/resources/2025_04/* lib/shopify_api/rest/resources/2025_07/
68
+ cp -r test/rest/2025_04/* test/rest/2025_07/
69
+ ```
70
+
71
+ ## Step 4: Update Test Files
72
+
73
+ After copying test files, you must update version-specific information in each test file.
74
+
75
+ ### Update Test Class Names
76
+ Change the class name to include the new version:
77
+
78
+ ```ruby
79
+ # From
80
+ class AbandonedCheckout202504Test < Test::Unit::TestCase
81
+
82
+ # To
83
+ class AbandonedCheckout202507Test < Test::Unit::TestCase
84
+ ```
85
+
86
+ **Naming Pattern:** `{ResourceName}{YYYYMM}Test`
87
+ - Remove underscores from the version (e.g., `202507` not `2025_07`)
88
+
89
+ ### Update Context API Version
90
+ In the `setup` method, update the API version:
91
+
92
+ ```ruby
93
+ def setup
94
+ super
95
+ test_session = ShopifyAPI::Auth::Session.new(id: "id", shop: "test-shop.myshopify.io", access_token: "this_is_a_test_token")
96
+ ShopifyAPI::Context.activate_session(test_session)
97
+
98
+ # Update this line:
99
+ modify_context(api_version: "2025-07") # Was "2025-04"
100
+ end
101
+ ```
102
+
103
+ ### Update URLs in Stub Requests
104
+ Update all API URLs in the test methods:
105
+
106
+ ```ruby
107
+ # From
108
+ stub_request(:get, "https://test-shop.myshopify.io/admin/api/2025-04/checkouts.json")
109
+
110
+ # To
111
+ stub_request(:get, "https://test-shop.myshopify.io/admin/api/2025-07/checkouts.json")
112
+ ```
113
+
114
+ ## Step 5: Handle Breaking Changes
115
+
116
+ ### Identify Removed Resources
117
+ In this example, `CustomerAddress` was removed in 2025-07.
118
+
119
+ ### Remove Deprecated Resources
120
+ If a resource is removed:
121
+ ```bash
122
+ # Remove resource file
123
+ rm lib/shopify_api/rest/resources/{NEW_VERSION}/{resource_name}.rb
124
+
125
+ # Remove test file
126
+ rm test/rest/{NEW_VERSION}/{resource_name}_test.rb
127
+ ```
128
+
129
+ ### Update Modified Resources
130
+ If a resource has structural changes:
131
+ 1. Update the resource class attributes
132
+ 2. Modify the `@paths` array if endpoints changed
133
+ 3. Update method signatures if parameters changed
134
+ 4. Adjust test cases accordingly
135
+
136
+ ## Step 7: Run Tests
137
+
138
+ ### Execute Test Suite
139
+ ```bash
140
+ # Run all tests
141
+ bundle exec rake test
142
+
143
+ # Run specific version tests
144
+ bundle exec rake test TEST=test/rest/{NEW_VERSION}/*
145
+ ```
146
+
147
+ ## Checklist
148
+
149
+ - [ ] Added new version to `SUPPORTED_ADMIN_VERSIONS` in `admin_versions.rb`
150
+ - [ ] Updated `LATEST_SUPPORTED_ADMIN_VERSION` if applicable
151
+ - [ ] Updated `RELEASE_CANDIDATE_ADMIN_VERSION` if applicable
152
+ - [ ] Created `lib/shopify_api/rest/resources/{NEW_VERSION}/` directory
153
+ - [ ] Created `test/rest/{NEW_VERSION}/` directory
154
+ - [ ] Copied all resource files from previous version
155
+ - [ ] Copied all test files from previous version
156
+ - [ ] Updated test class names (e.g., `Article202507Test`)
157
+ - [ ] Updated API version in test contexts (`modify_context(api_version: "2025-07")`)
158
+ - [ ] Updated all API URLs in test stub requests
159
+ - [ ] Removed deprecated resources and their tests
160
+ - [ ] Updated any modified resources
161
+ - [ ] Run test suite successfully
@@ -28,7 +28,8 @@ ShopifyAPI::Context.setup(
28
28
  scope: "read_orders,read_products,etc",
29
29
  is_embedded: true, # Set to true if you are building an embedded app
30
30
  is_private: false, # Set to true if you are building a private app
31
- api_version: "2021-01" # The version of the API you would like to use
31
+ api_version: "2021-01", # The version of the API you would like to use
32
+ expiring_offline_access_tokens: true # Set to true to enable expiring offline access tokens with refresh tokens
32
33
  )
33
34
  ```
34
35