shopify_api 14.11.1 → 15.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 (93) 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 +2 -2
  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/CHANGELOG.md +9 -0
  9. data/Gemfile.lock +1 -1
  10. data/RELEASING.md +108 -17
  11. data/REST_RESOURCES.md +161 -0
  12. data/docs/usage/webhooks.md +0 -17
  13. data/lib/shopify_api/admin_versions.rb +1 -5
  14. data/lib/shopify_api/clients/graphql/storefront.rb +5 -11
  15. data/lib/shopify_api/context.rb +4 -4
  16. data/lib/shopify_api/rest/resources/2025_10/abandoned_checkout.rb +194 -0
  17. data/lib/shopify_api/rest/resources/2025_10/access_scope.rb +62 -0
  18. data/lib/shopify_api/rest/resources/2025_10/apple_pay_certificate.rb +109 -0
  19. data/lib/shopify_api/rest/resources/2025_10/application_charge.rb +113 -0
  20. data/lib/shopify_api/rest/resources/2025_10/application_credit.rb +95 -0
  21. data/lib/shopify_api/rest/resources/2025_10/article.rb +269 -0
  22. data/lib/shopify_api/rest/resources/2025_10/asset.rb +122 -0
  23. data/lib/shopify_api/rest/resources/2025_10/assigned_fulfillment_order.rb +92 -0
  24. data/lib/shopify_api/rest/resources/2025_10/balance.rb +58 -0
  25. data/lib/shopify_api/rest/resources/2025_10/blog.rb +166 -0
  26. data/lib/shopify_api/rest/resources/2025_10/cancellation_request.rb +87 -0
  27. data/lib/shopify_api/rest/resources/2025_10/carrier_service.rb +120 -0
  28. data/lib/shopify_api/rest/resources/2025_10/checkout.rb +213 -0
  29. data/lib/shopify_api/rest/resources/2025_10/collect.rb +146 -0
  30. data/lib/shopify_api/rest/resources/2025_10/collection.rb +114 -0
  31. data/lib/shopify_api/rest/resources/2025_10/collection_listing.rb +159 -0
  32. data/lib/shopify_api/rest/resources/2025_10/comment.rb +287 -0
  33. data/lib/shopify_api/rest/resources/2025_10/country.rb +141 -0
  34. data/lib/shopify_api/rest/resources/2025_10/currency.rb +61 -0
  35. data/lib/shopify_api/rest/resources/2025_10/custom_collection.rb +191 -0
  36. data/lib/shopify_api/rest/resources/2025_10/customer.rb +328 -0
  37. data/lib/shopify_api/rest/resources/2025_10/deprecated_api_call.rb +61 -0
  38. data/lib/shopify_api/rest/resources/2025_10/discount_code.rb +226 -0
  39. data/lib/shopify_api/rest/resources/2025_10/dispute.rb +115 -0
  40. data/lib/shopify_api/rest/resources/2025_10/dispute_evidence.rb +121 -0
  41. data/lib/shopify_api/rest/resources/2025_10/dispute_file_upload.rb +85 -0
  42. data/lib/shopify_api/rest/resources/2025_10/draft_order.rb +279 -0
  43. data/lib/shopify_api/rest/resources/2025_10/event.rb +152 -0
  44. data/lib/shopify_api/rest/resources/2025_10/fulfillment.rb +235 -0
  45. data/lib/shopify_api/rest/resources/2025_10/fulfillment_event.rb +167 -0
  46. data/lib/shopify_api/rest/resources/2025_10/fulfillment_order.rb +326 -0
  47. data/lib/shopify_api/rest/resources/2025_10/fulfillment_request.rb +116 -0
  48. data/lib/shopify_api/rest/resources/2025_10/fulfillment_service.rb +134 -0
  49. data/lib/shopify_api/rest/resources/2025_10/gift_card.rb +222 -0
  50. data/lib/shopify_api/rest/resources/2025_10/gift_card_adjustment.rb +122 -0
  51. data/lib/shopify_api/rest/resources/2025_10/image.rb +161 -0
  52. data/lib/shopify_api/rest/resources/2025_10/inventory_item.rb +112 -0
  53. data/lib/shopify_api/rest/resources/2025_10/inventory_level.rb +183 -0
  54. data/lib/shopify_api/rest/resources/2025_10/location.rb +171 -0
  55. data/lib/shopify_api/rest/resources/2025_10/locations_for_move.rb +60 -0
  56. data/lib/shopify_api/rest/resources/2025_10/marketing_event.rb +213 -0
  57. data/lib/shopify_api/rest/resources/2025_10/metafield.rb +348 -0
  58. data/lib/shopify_api/rest/resources/2025_10/mobile_platform_application.rb +120 -0
  59. data/lib/shopify_api/rest/resources/2025_10/order.rb +503 -0
  60. data/lib/shopify_api/rest/resources/2025_10/order_risk.rb +148 -0
  61. data/lib/shopify_api/rest/resources/2025_10/page.rb +198 -0
  62. data/lib/shopify_api/rest/resources/2025_10/payment.rb +98 -0
  63. data/lib/shopify_api/rest/resources/2025_10/payment_gateway.rb +147 -0
  64. data/lib/shopify_api/rest/resources/2025_10/payment_transaction.rb +117 -0
  65. data/lib/shopify_api/rest/resources/2025_10/payout.rb +101 -0
  66. data/lib/shopify_api/rest/resources/2025_10/policy.rb +73 -0
  67. data/lib/shopify_api/rest/resources/2025_10/price_rule.rb +227 -0
  68. data/lib/shopify_api/rest/resources/2025_10/product.rb +227 -0
  69. data/lib/shopify_api/rest/resources/2025_10/product_listing.rb +200 -0
  70. data/lib/shopify_api/rest/resources/2025_10/product_resource_feedback.rb +92 -0
  71. data/lib/shopify_api/rest/resources/2025_10/province.rb +136 -0
  72. data/lib/shopify_api/rest/resources/2025_10/recurring_application_charge.rb +184 -0
  73. data/lib/shopify_api/rest/resources/2025_10/redirect.rb +143 -0
  74. data/lib/shopify_api/rest/resources/2025_10/refund.rb +158 -0
  75. data/lib/shopify_api/rest/resources/2025_10/resource_feedback.rb +77 -0
  76. data/lib/shopify_api/rest/resources/2025_10/script_tag.rb +159 -0
  77. data/lib/shopify_api/rest/resources/2025_10/shipping_zone.rb +87 -0
  78. data/lib/shopify_api/rest/resources/2025_10/shop.rb +231 -0
  79. data/lib/shopify_api/rest/resources/2025_10/smart_collection.rb +220 -0
  80. data/lib/shopify_api/rest/resources/2025_10/storefront_access_token.rb +91 -0
  81. data/lib/shopify_api/rest/resources/2025_10/tender_transaction.rb +97 -0
  82. data/lib/shopify_api/rest/resources/2025_10/theme.rb +127 -0
  83. data/lib/shopify_api/rest/resources/2025_10/transaction.rb +194 -0
  84. data/lib/shopify_api/rest/resources/2025_10/usage_charge.rb +106 -0
  85. data/lib/shopify_api/rest/resources/2025_10/user.rb +142 -0
  86. data/lib/shopify_api/rest/resources/2025_10/variant.rb +212 -0
  87. data/lib/shopify_api/rest/resources/2025_10/webhook.rb +173 -0
  88. data/lib/shopify_api/version.rb +1 -1
  89. data/lib/shopify_api/webhooks/registration.rb +3 -3
  90. data/lib/shopify_api/webhooks/registry.rb +3 -13
  91. data/lib/shopify_api/webhooks/{handler.rb → webhook_handler.rb} +0 -12
  92. data/lib/shopify_api.rb +1 -1
  93. metadata +76 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a74f8e8dd48cdc2900573e00f7dc6bb4ba302608075c7b06c285ee5dab6ca8ed
4
- data.tar.gz: e7cf3797171b79502f913bb289b518f349841de3adc1f576753f403732f7ea1f
3
+ metadata.gz: 9730739b6693ca317bd357162beef7ad7424a5f584eadc345e8b53308724cd27
4
+ data.tar.gz: 5d4773a92f4f3dda6615b7e6e47a50ee96bfbb0b8015f4dbd6e519d851da119f
5
5
  SHA512:
6
- metadata.gz: 45a9b83fddf9151bc99ba13e3353a8ac42cbf6559442cc6133f2c587670f1bbb1638ab5e40d8a799d412fb6d6943acc0ca60e99838480f45292f2951cb2de67f
7
- data.tar.gz: 7ce124fc5e459a17c2230efc2577ace84922db124a7d79f3cf59693664507b319077558bd7a20146d2f0848c6eeb689eba535c3614e8443b546d3fa8583f75cf
6
+ metadata.gz: c5133fc7f61b53d0ee91c38848dad3f0afdc92070276caac0ad911ad0d122039c509ed88afb9a35f8ead5ee0332fbc7caa0782012d856c8886f426409d2826cd
7
+ data.tar.gz: 5f874a62238c6aef8f3383ed876104d895118a9e767f43143a4458327b40dce5ffd891ea05908737633bea8ba958840c49920e557090b9b05732611369a3ec8f
@@ -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:
@@ -16,9 +16,9 @@ jobs:
16
16
  - 3.2
17
17
  - 3.3
18
18
  steps:
19
- - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
19
+ - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
20
20
  - name: Set up Ruby ${{ matrix.version }}
21
- uses: ruby/setup-ruby@e34163cd15f4bb403dcd72d98e295997e6a55798 # v1.238.0
21
+ uses: ruby/setup-ruby@829114fc20da43a41d27359103ec7a63020954d4 # v1.255.0
22
22
  with:
23
23
  ruby-version: ${{ matrix.version }}
24
24
  - 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
data/CHANGELOG.md CHANGED
@@ -3,6 +3,15 @@
3
3
  Note: For changes to the API, see https://shopify.dev/changelog?filter=api
4
4
  ## Unreleased
5
5
 
6
+ ### 15.0.0
7
+
8
+ - ⚠️ [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.
9
+ - Add support for 2025-10 API version
10
+ - Updated `LATEST_SUPPORTED_ADMIN_VERSION` to `2025-10`
11
+ - [#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.
12
+
13
+ - [#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`)
14
+
6
15
  ## 14.11.1
7
16
 
8
17
  - [#1395](https://github.com/Shopify/shopify-api-ruby/pull/1395) use correct internal admin host for 1P app development
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 (15.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
@@ -29,26 +29,9 @@ module WebhookHandler
29
29
  end
30
30
  ```
31
31
 
32
- **Note:** As of version 13.5.0 the `ShopifyAPI::Webhooks::Handler` class is still available to be used but will be removed in a future version of the gem.
33
-
34
32
  ### Best Practices
35
33
  It is recommended that in order to respond quickly to the Shopify webhook request that the handler not do any heavy logic or network calls, rather it should simply enqueue the work in some job queue in order to be executed later.
36
34
 
37
- ### Webhook Handler for versions 13.4.0 and prior
38
- If you want to register for an http webhook you need to implement a webhook handler which the `shopify_api` gem can use to determine how to process your webhook. You can make multiple implementations (one per topic) or you can make one implementation capable of handling all the topics you want to subscribe to. To do this simply make a module or class that includes or extends `ShopifyAPI::Webhooks::Handler` and implement the handle method which accepts the following named parameters: topic: `String`, shop: `String`, and body: `Hash[String, untyped]`. An example implementation is shown below:
39
-
40
- ```ruby
41
- module WebhookHandler
42
- extend ShopifyAPI::Webhooks::Handler
43
-
44
- class << self
45
- def handle(topic:, shop:, body:)
46
- puts "Received webhook! topic: #{topic} shop: #{shop} body: #{body}"
47
- end
48
- end
49
- end
50
- ```
51
-
52
35
  ## Add to Webhook Registry
53
36
 
54
37
  The next step is to add all the webhooks you would like to subscribe to for any shop to the webhook registry. To do this you can call `ShopifyAPI::Webhooks::Registry.add_registration` for each webhook you would like to handle. `add_registration` accepts a topic string, a delivery_method symbol (currently supporting `:http`, `:event_bridge`, and `:pub_sub`), a webhook path (the relative path for an http webhook) and a handler. This only needs to be done once when the app is started and we recommend doing this at the same time that you setup `ShopifyAPI::Context`. An example is shown below to register an http webhook:
@@ -5,6 +5,7 @@ module ShopifyAPI
5
5
  module AdminVersions
6
6
  SUPPORTED_ADMIN_VERSIONS = T.let([
7
7
  "unstable",
8
+ "2026-01",
8
9
  "2025-10",
9
10
  "2025-07",
10
11
  "2025-04",
@@ -22,12 +23,7 @@ module ShopifyAPI
22
23
  "2022-04",
23
24
  "2022-01",
24
25
  ], T::Array[String])
25
-
26
- LATEST_SUPPORTED_ADMIN_VERSION = T.let("2025-07", String)
27
- RELEASE_CANDIDATE_ADMIN_VERSION = T.let("2025-10", String)
28
26
  end
29
27
 
30
28
  SUPPORTED_ADMIN_VERSIONS = ShopifyAPI::AdminVersions::SUPPORTED_ADMIN_VERSIONS
31
- LATEST_SUPPORTED_ADMIN_VERSION = ShopifyAPI::AdminVersions::LATEST_SUPPORTED_ADMIN_VERSION
32
- RELEASE_CANDIDATE_ADMIN_VERSION = ShopifyAPI::AdminVersions::RELEASE_CANDIDATE_ADMIN_VERSION
33
29
  end
@@ -8,21 +8,15 @@ module ShopifyAPI
8
8
  sig do
9
9
  params(
10
10
  shop: String,
11
- storefront_access_token: T.nilable(String),
12
11
  private_token: T.nilable(String),
13
12
  public_token: T.nilable(String),
14
13
  api_version: T.nilable(String),
15
14
  ).void
16
15
  end
17
- def initialize(shop, storefront_access_token = nil, private_token: nil, public_token: nil, api_version: nil)
18
- unless storefront_access_token.nil?
19
- warning = <<~WARNING
20
- DEPRECATED: Use the named parameters for the Storefront token instead of passing
21
- the public token as the second argument. Also, you may want to look into using
22
- the Storefront private access token instead:
23
- https://shopify.dev/docs/api/usage/authentication#getting-started-with-private-access
24
- WARNING
25
- ShopifyAPI::Logger.deprecated(warning, "15.0.0")
16
+ def initialize(shop, private_token: nil, public_token: nil, api_version: nil)
17
+ token = private_token || public_token
18
+ if token.nil?
19
+ raise ArgumentError, "Storefront client requires either private_token or public_token to be provided"
26
20
  end
27
21
 
28
22
  session = Auth::Session.new(
@@ -32,7 +26,7 @@ module ShopifyAPI
32
26
  is_online: false,
33
27
  )
34
28
  super(session: session, base_path: "/api", api_version: api_version)
35
- @storefront_access_token = T.let(T.must(private_token || public_token || storefront_access_token), String)
29
+ @storefront_access_token = T.let(token, String)
36
30
  @storefront_auth_header = T.let(
37
31
  private_token.nil? ? "X-Shopify-Storefront-Access-Token" : "Shopify-Storefront-Private-Token",
38
32
  String,
@@ -7,7 +7,7 @@ module ShopifyAPI
7
7
 
8
8
  @api_key = T.let("", String)
9
9
  @api_secret_key = T.let("", String)
10
- @api_version = T.let(LATEST_SUPPORTED_ADMIN_VERSION, String)
10
+ @api_version = T.let("", String)
11
11
  @api_host = T.let(nil, T.nilable(String))
12
12
  @scope = T.let(Auth::AuthScopes.new, Auth::AuthScopes)
13
13
  @is_private = T.let(false, T::Boolean)
@@ -101,8 +101,8 @@ module ShopifyAPI
101
101
  @rest_resource_loader&.setup
102
102
  @rest_resource_loader&.unload
103
103
 
104
- # No resources for the unstable version or the release candidate version
105
- return if api_version == "unstable" || api_version == RELEASE_CANDIDATE_ADMIN_VERSION
104
+ # No resources for the unstable version
105
+ return if api_version == "unstable"
106
106
 
107
107
  version_folder_name = api_version.gsub("-", "_")
108
108
 
@@ -155,7 +155,7 @@ module ShopifyAPI
155
155
 
156
156
  sig { returns(T::Boolean) }
157
157
  def setup?
158
- [api_key, api_secret_key, T.must(host)].none?(&:empty?)
158
+ [api_key, api_secret_key, api_version, T.must(host)].none?(&:empty?)
159
159
  end
160
160
 
161
161
  sig { returns(T.nilable(Auth::Session)) }