Class: Nfe::Resources::Webhooks

Inherits:
AbstractResource show all
Defined in:
lib/nfe/resources/webhooks.rb,
sig/nfe/resources/webhooks.rbs

Overview

Webhooks resource on the :main host family.

Webhooks are managed at the account level over /v2/webhooks — use the *_account_webhook* methods. The live API wraps create/update requests and single-object responses in a webHook envelope; the SDK envelopes/unwraps transparently. Contract source of truth: openapi/nf-servico-v1.yaml plus live probes (2026-07-02/03).

The company-scoped methods (+list+/+create+/+retrieve+/+update+/ +delete+/+test+ under /v1/companies/{id}/webhooks) are deprecated: the route returns 404 on the current API (confirmed on three accounts, 2026-07-02/03). They remain, unchanged, until the next major.

Also exposes a thin #verify_signature delegation to Webhook (the canonical signature-verification API is the module).

Constant Summary collapse

AVAILABLE_EVENTS =
Deprecated.

These literals do not exist on the live API — the real event types follow +service_invoice.+/+product_invoice.+/ consumer_invoice.* (46 ids live). Use #fetch_event_types.

Legacy static list of event types.

Returns:

  • (Array[String])
%w[
  invoice.issued
  invoice.cancelled
  invoice.failed
  invoice.processing
  company.created
  company.updated
  company.deleted
].freeze

Instance Attribute Summary

Attributes inherited from AbstractResource

#client

Instance Method Summary collapse

Methods inherited from AbstractResource

#api_version, #build_list_page, #build_multipart_body, #cursor_list_page, #dig_key, #download, #extract_invoice_id, #get, #handle_async_response, #hydrate, #hydrate_list, #initialize, #multipart_part, #page_list_page, #parse_json, #post, #put, #unwrap, #upload_multipart

Constructor Details

This class inherits a constructor from Nfe::Resources::AbstractResource

Instance Method Details

#api_familySymbol

Returns:

  • (Symbol)


50
51
52
# File 'lib/nfe/resources/webhooks.rb', line 50

def api_family
  :main
end

#create(company_id, data) ⇒ Nfe::WebhookSubscription?

Deprecated.

The /v1/companies/{id}/webhooks route returns 404 on the current API (confirmed on three accounts, 2026-07-02/03). Use #create_account_webhook.

Create a webhook subscription. Accepts url, events, secret, active.

Parameters:

  • company_id (String)
  • data (Hash)

Returns:



211
212
213
214
215
216
# File 'lib/nfe/resources/webhooks.rb', line 211

def create(company_id, data)
  id = Nfe::IdValidator.company_id(company_id)
  response = post("/companies/#{id}/webhooks",
                  body: json_body(data), headers: json_headers)
  hydrate(Nfe::WebhookSubscription, parse_json(response.body))
end

#create_account_webhook(data) ⇒ Nfe::AccountWebhook

Create an account webhook (+POST /v2/webhooks+).

The request is wrapped in the mandatory webHook envelope (the API rejects a bare body with 400 "missing required properties: 'webHook'") and the 201 {"webHook": {...}} response is unwrapped.

NFE.io pings the uri at creation time and requires a 2xx response — the endpoint must already be live, or the create fails. secret must be 32–64 characters; it is echoed back on create and omitted on subsequent reads.

Parameters:

  • data (Hash)

    webhook attributes in wire (camelCase) keys, e.g. +{ uri: "https://...&quot;, contentType: "json", secret: "<32-64 chars>", filters: ["service_invoice.issued_successfully"], status: "Active" }+. Discover valid filters with #fetch_event_types.

Returns:



92
93
94
95
96
# File 'lib/nfe/resources/webhooks.rb', line 92

def (data)
  response = post("/v2/webhooks",
                  body: json_body({ webHook: data }), headers: json_headers)
  (response)
end

#delete(company_id, webhook_id) ⇒ nil

Deprecated.

The /v1/companies/{id}/webhooks route returns 404 on the current API (confirmed on three accounts, 2026-07-02/03). Use #delete_account_webhook.

Delete a webhook.

Parameters:

  • company_id (String)
  • webhook_id (String)

Returns:

  • (nil)


261
262
263
264
265
266
# File 'lib/nfe/resources/webhooks.rb', line 261

def delete(company_id, webhook_id)
  id = Nfe::IdValidator.company_id(company_id)
  wid = Nfe::IdValidator.presence!(webhook_id, "webhook_id")
  super("/companies/#{id}/webhooks/#{wid}")
  nil
end

#delete_account_webhook(webhook_id) ⇒ nil

Delete a single account webhook by id (+DELETE /v2/webhooks/id+).

Parameters:

  • webhook_id (String)

Returns:

  • (nil)


141
142
143
144
145
# File 'lib/nfe/resources/webhooks.rb', line 141

def (webhook_id)
  wid = Nfe::IdValidator.presence!(webhook_id, "webhook_id")
  http_delete("/v2/webhooks/#{wid}")
  nil
end

#delete_all_account_webhooksnil

⚠️ DESTRUCTIVE: delete ALL of the account's webhooks (+DELETE /v2/webhooks+). Named distinctly from #delete_account_webhook so it can never be reached by a mistyped single delete.

Returns:

  • (nil)


153
154
155
156
# File 'lib/nfe/resources/webhooks.rb', line 153

def 
  http_delete("/v2/webhooks")
  nil
end

#fetch_event_typesArray<String>

Fetch the live list of webhook event types (+GET /v2/webhooks/eventTypes+).

The API wraps the result as {"eventTypes": [{ "id": ... }, ...]}; this extracts the ids (e.g. "service_invoice.issued_successfully", "product_invoice.issued" — 46 ids live). Use these as filters when creating or updating a webhook.

Returns:

  • (Array<String>)


178
179
180
181
182
183
184
# File 'lib/nfe/resources/webhooks.rb', line 178

def fetch_event_types
  response = get("/v2/webhooks/eventTypes")
  payload = parse_json(response.body)
  items = [] #: Array[untyped]
  items = payload["eventTypes"] || items if payload.is_a?(Hash)
  items.map { |item| item["id"] }.compact
end

#full_path(path) ⇒ String

Account-scoped endpoints live under /v2 on the same :main host, while the (deprecated) company-scoped ones keep the resource default /v1. A path that already carries an explicit version segment passes through unprefixed.

Parameters:

  • path (String)

Returns:

  • (String)


58
59
60
# File 'lib/nfe/resources/webhooks.rb', line 58

def full_path(path)
  path.start_with?("/v2/") ? path : super
end

#get_available_eventsArray<String>

Deprecated.

These literals do not exist on the live API. Use #fetch_event_types for the real, live list.

The legacy static list of webhook event types.

Returns:

  • (Array<String>)


292
293
294
# File 'lib/nfe/resources/webhooks.rb', line 292

def get_available_events
  AVAILABLE_EVENTS.dup
end

#http_deleteNfe::Http::Response

Preserve the inherited HTTP DELETE helper under a private name before the public company-scoped delete shadows it — the account-scoped deletes still need the raw verb.

Parameters:

  • path (String)
  • query: (Hash[untyped, untyped])
  • request_options: (Nfe::RequestOptions, nil)
  • headers: (Hash[String, String])

Returns:



30
# File 'lib/nfe/resources/webhooks.rb', line 30

alias http_delete delete

#hydrate_account_webhook(response) ⇒ Nfe::AccountWebhook?

Unwrap a single-object {"webHook": {...}} envelope (raw-body fallback) and hydrate an AccountWebhook.

Parameters:

Returns:



308
309
310
# File 'lib/nfe/resources/webhooks.rb', line 308

def (response)
  hydrate(Nfe::AccountWebhook, unwrap(parse_json(response.body), "webHook"))
end

#json_body(data) ⇒ String

Parameters:

  • data (Object)

Returns:

  • (String)


316
317
318
# File 'lib/nfe/resources/webhooks.rb', line 316

def json_body(data)
  JSON.generate(data)
end

#json_headersHash[String, String]

Returns:

  • (Hash[String, String])


312
313
314
# File 'lib/nfe/resources/webhooks.rb', line 312

def json_headers
  { "Content-Type" => "application/json" }
end

#list(company_id) ⇒ Nfe::ListResponse

Deprecated.

The /v1/companies/{id}/webhooks route returns 404 on the current API (confirmed on three accounts, 2026-07-02/03). Use #list_account_webhooks.

List a company's webhook subscriptions.

Parameters:

  • company_id (String)

Returns:



194
195
196
197
198
199
200
# File 'lib/nfe/resources/webhooks.rb', line 194

def list(company_id)
  id = Nfe::IdValidator.company_id(company_id)
  response = get("/companies/#{id}/webhooks")
  payload = parse_json(response.body)
  items = webhook_items(payload).map { |item| hydrate(Nfe::WebhookSubscription, item) }
  Nfe::ListResponse.new(data: items)
end

#list_account_webhooksNfe::ListResponse

List the account's webhooks (+GET /v2/webhooks+).

The API wraps the collection as {"webHooks": [...]}; the SDK unwraps it into an ListResponse of AccountWebhook. secret is omitted on reads.

Returns:



71
72
73
74
# File 'lib/nfe/resources/webhooks.rb', line 71

def 
  response = get("/v2/webhooks")
  hydrate_list(Nfe::AccountWebhook, parse_json(response.body), wrapper_key: "webHooks")
end

#ping_account_webhook(webhook_id) ⇒ nil

Trigger a test ping for an account webhook (+PUT /v2/webhooks/id/pings+, responds 204).

Parameters:

  • webhook_id (String)

Returns:

  • (nil)


163
164
165
166
167
# File 'lib/nfe/resources/webhooks.rb', line 163

def (webhook_id)
  wid = Nfe::IdValidator.presence!(webhook_id, "webhook_id")
  put("/v2/webhooks/#{wid}/pings", body: json_body({}), headers: json_headers)
  nil
end

#retrieve(company_id, webhook_id) ⇒ Nfe::WebhookSubscription?

Deprecated.

The /v1/companies/{id}/webhooks route returns 404 on the current API (confirmed on three accounts, 2026-07-02/03). Use #retrieve_account_webhook.

Retrieve a webhook by id.

Parameters:

  • company_id (String)
  • webhook_id (String)

Returns:



227
228
229
230
231
232
# File 'lib/nfe/resources/webhooks.rb', line 227

def retrieve(company_id, webhook_id)
  id = Nfe::IdValidator.company_id(company_id)
  wid = Nfe::IdValidator.presence!(webhook_id, "webhook_id")
  response = get("/companies/#{id}/webhooks/#{wid}")
  hydrate(Nfe::WebhookSubscription, parse_json(response.body))
end

#retrieve_account_webhook(webhook_id) ⇒ Nfe::AccountWebhook

Retrieve an account webhook by id (+GET /v2/webhooks/id+).

Unwraps the {"webHook": {...}} envelope, falling back to the raw body when the envelope is absent. secret is omitted on reads.

Parameters:

  • webhook_id (String)

Returns:



105
106
107
108
109
# File 'lib/nfe/resources/webhooks.rb', line 105

def (webhook_id)
  wid = Nfe::IdValidator.presence!(webhook_id, "webhook_id")
  response = get("/v2/webhooks/#{wid}")
  (response)
end

#test(company_id, webhook_id) ⇒ Hash

Deprecated.

The /v1/companies/{id}/webhooks route returns 404 on the current API (confirmed on three accounts, 2026-07-02/03). Use #ping_account_webhook.

Trigger a synthetic delivery to verify a webhook is reachable.

Parameters:

  • company_id (String)
  • webhook_id (String)

Returns:

  • (Hash)

    { success: bool, message: String? }.



277
278
279
280
281
282
283
284
# File 'lib/nfe/resources/webhooks.rb', line 277

def test(company_id, webhook_id)
  id = Nfe::IdValidator.company_id(company_id)
  wid = Nfe::IdValidator.presence!(webhook_id, "webhook_id")
  response = post("/companies/#{id}/webhooks/#{wid}/test",
                  body: json_body({}), headers: json_headers)
  payload = parse_json(response.body) || {}
  { success: payload["success"] || false, message: payload["message"] }
end

#update(company_id, webhook_id, data) ⇒ Nfe::WebhookSubscription?

Deprecated.

The /v1/companies/{id}/webhooks route returns 404 on the current API (confirmed on three accounts, 2026-07-02/03). Use #update_account_webhook.

Update a webhook.

Parameters:

  • company_id (String)
  • webhook_id (String)
  • data (Hash)

Returns:



244
245
246
247
248
249
250
# File 'lib/nfe/resources/webhooks.rb', line 244

def update(company_id, webhook_id, data)
  id = Nfe::IdValidator.company_id(company_id)
  wid = Nfe::IdValidator.presence!(webhook_id, "webhook_id")
  response = put("/companies/#{id}/webhooks/#{wid}",
                 body: json_body(data), headers: json_headers)
  hydrate(Nfe::WebhookSubscription, parse_json(response.body))
end

#update_account_webhook(webhook_id, data) ⇒ Nfe::AccountWebhook

Note:

+PUT+ is a full replacement (live-confirmed 2026-07-03): omitted fields reset to their defaults — an update without status deactivates the webhook. Always send the complete object, starting from a retrieve:

current = client.webhooks.retrieve_account_webhook(id)
client.webhooks.update_account_webhook(id, {
uri: current.uri,
contentType: current.content_type,
status: current.status,            # keep it "Active"!
filters: ["service_invoice.issued_successfully"]
})

Update an account webhook (+PUT /v2/webhooks/id+), request wrapped in the webHook envelope.

Parameters:

  • webhook_id (String)
  • data (Hash)

    the complete webhook attributes (wire camelCase keys).

Returns:



130
131
132
133
134
135
# File 'lib/nfe/resources/webhooks.rb', line 130

def (webhook_id, data)
  wid = Nfe::IdValidator.presence!(webhook_id, "webhook_id")
  response = put("/v2/webhooks/#{wid}",
                 body: json_body({ webHook: data }), headers: json_headers)
  (response)
end

#verify_signature(payload:, signature:, secret:) ⇒ Boolean

Verify a webhook signature. Thin delegation to Webhook for Node parity; the canonical API is the module. Never raises.

Parameters:

  • payload: (String)
  • signature: (String, Array[String], nil)
  • secret: (String, nil)

Returns:

  • (Boolean)


300
301
302
# File 'lib/nfe/resources/webhooks.rb', line 300

def verify_signature(payload:, signature:, secret:)
  Nfe::Webhook.verify_signature(payload: payload, signature: signature, secret: secret)
end

#webhook_items(payload) ⇒ Array[untyped]

Tolerate either a bare array, a +data+-wrapped list, or a webhooks envelope for the (deprecated) company-scoped list response.

Parameters:

  • payload (Object)

Returns:

  • (Array[untyped])


322
323
324
325
326
327
# File 'lib/nfe/resources/webhooks.rb', line 322

def webhook_items(payload)
  return payload if payload.is_a?(Array)
  return [] unless payload.is_a?(Hash)

  payload["data"] || payload["webhooks"] || payload[:data] || payload[:webhooks] || []
end