tango-api-client 0.1.1 → 0.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +15 -0
- data/lib/tango/api/client/version.rb +1 -1
- data/lib/tango/api/client.rb +10 -0
- data/lib/tango/api/resources/base.rb +13 -0
- data/lib/tango/api/resources/brand_categories.rb +15 -0
- data/lib/tango/api/resources/webhooks.rb +71 -0
- data/sig/tango/api/client.rbs +1 -0
- metadata +5 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f7475c292cfcb29d85404d80d86cb94f47c4d0497dcfd97743366be0af176933
|
|
4
|
+
data.tar.gz: 69d61b9a8d860fd5734557d61aec61ae8d969634803c3a97e87f23db9ead35e1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1243790a92ce6dba4870e506fb86e00a9436bf7c9c6e206e6d7d908b7011a0a06139ee0ba2decd3f6d0b4dd1341bd856484b66c7ad252886b88f091cb0faebc3
|
|
7
|
+
data.tar.gz: 6205cc363c7e1d2ef985b31fedb377a53c242d9d7339568d1bb5480be0aa8aecfc249fb1b71dc3b05efc4d208ef8e65311c405cb40244f31b0029404fa2262be
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
- Nothing yet.
|
|
7
7
|
|
|
8
|
+
## [0.2.0] - 2026-11-09
|
|
9
|
+
- Add Webhooks resource for subscription management: `create`, `list`, `get`, `update`, `delete`, `renew`
|
|
10
|
+
- Add webhook event history and redelivery: `events` (cursor paging, revision range) and `replay` (`fromRevision`/`toRevision` query params)
|
|
11
|
+
- Add `test` to trigger Tango's test deliveries (`ConnectivityTest`, or an event type such as `ItemAvailability` in the sandbox)
|
|
12
|
+
- `Resources::Base#post_without_body` for POST action endpoints that take only path and query parameters
|
|
13
|
+
|
|
14
|
+
## [0.1.2] - 2025-11-12
|
|
15
|
+
- Add Brand Categories resource: `get` method for `/brandCategories` endpoint
|
|
16
|
+
|
|
17
|
+
## [0.1.1] - 2025-11-12
|
|
18
|
+
- (Version already published)
|
|
19
|
+
|
|
8
20
|
## [0.1.0] - 2025-11-07
|
|
9
21
|
- Initial release
|
|
10
22
|
- Basic and OAuth2 auth strategies
|
data/README.md
CHANGED
|
@@ -115,6 +115,19 @@ client.orders.create(
|
|
|
115
115
|
|
|
116
116
|
# Resend with Idempotency-Key (prevents duplicate resends)
|
|
117
117
|
client.orders.resend('ORDER-123', idempotency_key: idempotency)
|
|
118
|
+
|
|
119
|
+
# Webhook subscriptions (HMAC-signed ItemAvailability events)
|
|
120
|
+
sub = client.webhooks.create(
|
|
121
|
+
url: 'https://example.com/v1/tango/webhooks',
|
|
122
|
+
eventTypes: ['ItemAvailability'],
|
|
123
|
+
headers: [{ name: 'X-Subscription-Generation', value: '1' }],
|
|
124
|
+
payloadVerificationMethod: 'HMAC',
|
|
125
|
+
hmacSharedSecretKey: Base64.strict_encode64(SecureRandom.bytes(32))
|
|
126
|
+
)
|
|
127
|
+
client.webhooks.renew(sub['webhookId']) # => { 'webhookId', 'expiresAt' }
|
|
128
|
+
client.webhooks.events(sub['webhookId'], fromRevision: 0, maxResults: 100)
|
|
129
|
+
client.webhooks.replay(sub['webhookId'], from_revision: 0) # redeliver up to 3 months back
|
|
130
|
+
client.webhooks.test(sub['webhookId'], 'ItemAvailability') # sandbox only
|
|
118
131
|
```
|
|
119
132
|
|
|
120
133
|
### Resources overview
|
|
@@ -122,6 +135,7 @@ client.orders.resend('ORDER-123', idempotency_key: idempotency)
|
|
|
122
135
|
| Resource | Class | Methods (args) | HTTP / Path |
|
|
123
136
|
|-----------|-----------------------------------|----------------------------------------------------------------------------------------|----------------------------------------------------|
|
|
124
137
|
| Catalogs | `Tango::Api::Resources::Catalogs` | `get(params = {})` | GET `/catalogs` |
|
|
138
|
+
| Brand Categories | `Tango::Api::Resources::BrandCategories` | `get` | GET `/brandCategories` |
|
|
125
139
|
| Orders | `Tango::Api::Resources::Orders` | `create(body)`, `get(order_id)`, `list(params = {})`, `resend(order_id)` | POST `/orders`; GET `/orders/{id}`; GET `/orders`; POST `/orders/{id}/resend` |
|
|
126
140
|
| Accounts | `Tango::Api::Resources::Accounts` | `get(account_identifier)`, `list_for_customer(customer_identifier, params)`, `create(customer_identifier, body)`, `update_under_customer(customer_identifier, account_identifier, body)`, low balance alerts: `list_low_balance_alerts`, `set_low_balance_alert`, `get_low_balance_alert`, `update_low_balance_alert`, `delete_low_balance_alert` | GET `/accounts/{accountIdentifier}`; GET/POST/PATCH/DELETE under `/customers/{customerIdentifier}/accounts/...` |
|
|
127
141
|
| Customers | `Tango::Api::Resources::Customers`| `list(params = {})`, `get(customer_identifier)`, `create(body)`, `accounts(customer_identifier, params)` | GET `/customers`; GET `/customers/{customerIdentifier}`; POST `/customers`; GET `/customers/{customerIdentifier}/accounts` |
|
|
@@ -129,6 +143,7 @@ client.orders.resend('ORDER-123', idempotency_key: idempotency)
|
|
|
129
143
|
| Status | `Tango::Api::Resources::Status` | `get` | GET `/status` |
|
|
130
144
|
| Exchange Rates | `Tango::Api::Resources::ExchangeRates` | `get(params = {})`, `get_for_utid(utid, params = {})` | GET `/exchangeRates`; GET `/exchangeRates/{utid}` |
|
|
131
145
|
| Choice Products | `Tango::Api::Resources::ChoiceProducts` | `get(params = {})`, `get_for_utid(utid)`, `catalog(choice_product_utid, params = {})` | GET `/choiceProducts`; GET `/choiceProducts/{utid}`; GET `/choiceProducts/{utid}/catalog` |
|
|
146
|
+
| Webhooks | `Tango::Api::Resources::Webhooks` | `create(body)`, `list(params = {})`, `get(webhook_id)`, `update(webhook_id, body)`, `delete(webhook_id)`, `renew(webhook_id)`, `events(webhook_id, params = {})`, `replay(webhook_id, from_revision:, to_revision: nil)`, `test(webhook_id, test_name)` | POST/GET `/webhooks`; GET/PATCH/DELETE `/webhooks/{webhookId}`; POST `/webhooks/{webhookId}/renew`; GET `/webhooks/{webhookId}/events`; POST `/webhooks/{webhookId}/replay`; POST `/webhooks/{webhookId}/tests/{testName}` |
|
|
132
147
|
|
|
133
148
|
### Smoke test
|
|
134
149
|
|
data/lib/tango/api/client.rb
CHANGED
|
@@ -19,6 +19,8 @@ require_relative "resources/customers"
|
|
|
19
19
|
require_relative "resources/status"
|
|
20
20
|
require_relative "resources/exchange_rates"
|
|
21
21
|
require_relative "resources/choice_products"
|
|
22
|
+
require_relative "resources/brand_categories"
|
|
23
|
+
require_relative "resources/webhooks"
|
|
22
24
|
|
|
23
25
|
module Tango
|
|
24
26
|
module Api
|
|
@@ -78,6 +80,14 @@ module Tango
|
|
|
78
80
|
Resources::ChoiceProducts.new(@conn)
|
|
79
81
|
end
|
|
80
82
|
|
|
83
|
+
def brand_categories
|
|
84
|
+
Resources::BrandCategories.new(@conn)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def webhooks
|
|
88
|
+
Resources::Webhooks.new(@conn)
|
|
89
|
+
end
|
|
90
|
+
|
|
81
91
|
private
|
|
82
92
|
|
|
83
93
|
def build_connection
|
|
@@ -53,6 +53,19 @@ module Tango
|
|
|
53
53
|
raise map_faraday_error(e)
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
+
# POST with no request body, for action endpoints that take only path and query
|
|
57
|
+
# parameters (e.g. webhook renew, replay, tests). Empty or non-JSON success bodies
|
|
58
|
+
# such as "OK" are returned as {} or { "raw" => body }.
|
|
59
|
+
def post_without_body(path, params = nil)
|
|
60
|
+
response = @conn.post(path) { |req| req.params.update(params) if params }
|
|
61
|
+
ensure_success_or_raise(response)
|
|
62
|
+
return {} if response.body.to_s.strip.empty?
|
|
63
|
+
|
|
64
|
+
parse_json_response(response)
|
|
65
|
+
rescue Faraday::Error => e
|
|
66
|
+
raise map_faraday_error(e)
|
|
67
|
+
end
|
|
68
|
+
|
|
56
69
|
def delete_json(path)
|
|
57
70
|
response = @conn.delete(path)
|
|
58
71
|
ensure_success_or_raise(response)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tango
|
|
4
|
+
module Api
|
|
5
|
+
module Resources
|
|
6
|
+
# Resource for Brand Categories endpoints.
|
|
7
|
+
class BrandCategories < Base
|
|
8
|
+
# GET /brandCategories
|
|
9
|
+
def get
|
|
10
|
+
get_json("brandCategories")
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tango
|
|
4
|
+
module Api
|
|
5
|
+
module Resources
|
|
6
|
+
# Webhook subscriptions: create, manage, renew, and read or redeliver past events.
|
|
7
|
+
class Webhooks < Base
|
|
8
|
+
# POST /webhooks
|
|
9
|
+
# Body keys: url (required), eventTypes and/or categories, headers ([{ name:, value: }]),
|
|
10
|
+
# payloadVerificationMethod ("HMAC", "X509" or "NONE"), hmacSharedSecretKey (base64),
|
|
11
|
+
# signingCertificate (base64).
|
|
12
|
+
# Returns { "webhookId" => ..., "expiresAt" => ... }.
|
|
13
|
+
def create(body)
|
|
14
|
+
post_json("webhooks", body)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# GET /webhooks
|
|
18
|
+
# Params may include: prevCursor, nextCursor, maxResults (default 10, max 200), url,
|
|
19
|
+
# headerName, headerValue, categories, eventTypes, expiresAtFrom/To, createdAtFrom/To.
|
|
20
|
+
def list(params = {})
|
|
21
|
+
get_json("webhooks", params)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# GET /webhooks/{webhookId}
|
|
25
|
+
def get(webhook_id)
|
|
26
|
+
get_json("webhooks/#{webhook_id}")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# PATCH /webhooks/{webhookId}
|
|
30
|
+
# Body keys as for #create; all optional.
|
|
31
|
+
def update(webhook_id, body)
|
|
32
|
+
patch_json("webhooks/#{webhook_id}", body)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# DELETE /webhooks/{webhookId}
|
|
36
|
+
def delete(webhook_id)
|
|
37
|
+
delete_json("webhooks/#{webhook_id}")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# POST /webhooks/{webhookId}/renew
|
|
41
|
+
# Returns { "webhookId" => ..., "expiresAt" => ... }.
|
|
42
|
+
def renew(webhook_id)
|
|
43
|
+
post_without_body("webhooks/#{webhook_id}/renew")
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# GET /webhooks/{webhookId}/events
|
|
47
|
+
# Params may include: fromRevision, toRevision, prevCursor, nextCursor, maxResults.
|
|
48
|
+
# Returns a page: { "items" => [...], "nextCursor", "nextPageAvailable", ... }.
|
|
49
|
+
def events(webhook_id, params = {})
|
|
50
|
+
get_json("webhooks/#{webhook_id}/events", params)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# POST /webhooks/{webhookId}/replay?fromRevision=&toRevision=
|
|
54
|
+
# Redelivers past events (up to three months old). Omitting to_revision replays
|
|
55
|
+
# through the latest event.
|
|
56
|
+
def replay(webhook_id, from_revision:, to_revision: nil)
|
|
57
|
+
params = { fromRevision: from_revision }
|
|
58
|
+
params[:toRevision] = to_revision unless to_revision.nil?
|
|
59
|
+
post_without_body("webhooks/#{webhook_id}/replay", params)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# POST /webhooks/{webhookId}/tests/{testName}
|
|
63
|
+
# testName: ConnectivityTest (any environment) or, in the sandbox only, an event type
|
|
64
|
+
# such as ItemAvailability.
|
|
65
|
+
def test(webhook_id, test_name)
|
|
66
|
+
post_without_body("webhooks/#{webhook_id}/tests/#{test_name}")
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
data/sig/tango/api/client.rbs
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tango-api-client
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Puneeth Kumar DN
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: activesupport
|
|
@@ -88,6 +87,7 @@ files:
|
|
|
88
87
|
- lib/tango/api/errors.rb
|
|
89
88
|
- lib/tango/api/resources/accounts.rb
|
|
90
89
|
- lib/tango/api/resources/base.rb
|
|
90
|
+
- lib/tango/api/resources/brand_categories.rb
|
|
91
91
|
- lib/tango/api/resources/catalogs.rb
|
|
92
92
|
- lib/tango/api/resources/choice_products.rb
|
|
93
93
|
- lib/tango/api/resources/customers.rb
|
|
@@ -95,6 +95,7 @@ files:
|
|
|
95
95
|
- lib/tango/api/resources/funds.rb
|
|
96
96
|
- lib/tango/api/resources/orders.rb
|
|
97
97
|
- lib/tango/api/resources/status.rb
|
|
98
|
+
- lib/tango/api/resources/webhooks.rb
|
|
98
99
|
- sig/tango/api/client.rbs
|
|
99
100
|
homepage: https://github.com/Engagedly-Inc/tango-api-client
|
|
100
101
|
licenses:
|
|
@@ -104,7 +105,6 @@ metadata:
|
|
|
104
105
|
source_code_uri: https://github.com/Engagedly-Inc/tango-api-client
|
|
105
106
|
changelog_uri: https://github.com/Engagedly-Inc/tango-api-client/blob/master/CHANGELOG.md
|
|
106
107
|
rubygems_mfa_required: 'true'
|
|
107
|
-
post_install_message:
|
|
108
108
|
rdoc_options: []
|
|
109
109
|
require_paths:
|
|
110
110
|
- lib
|
|
@@ -119,8 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
119
119
|
- !ruby/object:Gem::Version
|
|
120
120
|
version: '0'
|
|
121
121
|
requirements: []
|
|
122
|
-
rubygems_version: 3.
|
|
123
|
-
signing_key:
|
|
122
|
+
rubygems_version: 3.6.9
|
|
124
123
|
specification_version: 4
|
|
125
124
|
summary: Ruby client for Tango (BHN) API with dual auth and robust errors.
|
|
126
125
|
test_files: []
|