Class: Whatsapp::MessageTemplates

Inherits:
Object
  • Object
show all
Includes:
ResponseHandling
Defined in:
lib/ruby/whatsapp/message_templates.rb,
lib/ruby/whatsapp/message_templates/button.rb,
lib/ruby/whatsapp/message_templates/example.rb,
lib/ruby/whatsapp/message_templates/response.rb,
lib/ruby/whatsapp/message_templates/statuses.rb,
lib/ruby/whatsapp/message_templates/template.rb,
lib/ruby/whatsapp/message_templates/component.rb,
lib/ruby/whatsapp/message_templates/button/otp.rb,
lib/ruby/whatsapp/message_templates/button/url.rb,
lib/ruby/whatsapp/message_templates/categories.rb,
lib/ruby/whatsapp/message_templates/button/base.rb,
lib/ruby/whatsapp/message_templates/placeholders.rb,
lib/ruby/whatsapp/message_templates/value_object.rb,
lib/ruby/whatsapp/message_templates/component_set.rb,
lib/ruby/whatsapp/message_templates/response/node.rb,
lib/ruby/whatsapp/message_templates/component/base.rb,
lib/ruby/whatsapp/message_templates/component/body.rb,
lib/ruby/whatsapp/message_templates/response/paging.rb,
lib/ruby/whatsapp/message_templates/button/copy_code.rb,
lib/ruby/whatsapp/message_templates/component/footer.rb,
lib/ruby/whatsapp/message_templates/component/header.rb,
lib/ruby/whatsapp/message_templates/library_template.rb,
lib/ruby/whatsapp/message_templates/response/created.rb,
lib/ruby/whatsapp/message_templates/response/summary.rb,
lib/ruby/whatsapp/message_templates/component/buttons.rb,
lib/ruby/whatsapp/message_templates/parameter_formats.rb,
lib/ruby/whatsapp/message_templates/button/quick_reply.rb,
lib/ruby/whatsapp/message_templates/component/carousel.rb,
lib/ruby/whatsapp/message_templates/button/phone_number.rb,
lib/ruby/whatsapp/message_templates/response/collection.rb,
lib/ruby/whatsapp/message_templates/response/quality_score.rb,
lib/ruby/whatsapp/message_templates/component/carousel/card.rb,
lib/ruby/whatsapp/message_templates/button/otp/supported_app.rb,
lib/ruby/whatsapp/message_templates/component/limited_time_offer.rb,
lib/ruby/whatsapp/message_templates/library_template/body_inputs.rb,
lib/ruby/whatsapp/message_templates/library_template/button_inputs.rb

Overview

Manages the message templates on a WhatsApp Business Account: create, list, read, edit, and delete.

This is the opposite side of Whatsapp::Messages::Template, which sends an already-approved template. The two are separate APIs with incompatible payload schemas — different endpoint, different ID (waba_id, not phone_id), different permission (whatsapp_business_management), and components that carry text plus an example here versus parameters when sending. See lib/ruby/whatsapp/message_templates/CLAUDE.md.

This class is only the transport: it builds paths, issues requests, and hands the bodies to Response. Every rule about what a valid template looks like lives in Template / ComponentSet / Component / Button, so nothing here needs to know what a carousel is.

Source: https://developers.facebook.com/docs/graph-api/reference/whats-app-business-account/message_templates/

Examples:

templates = Whatsapp::MessageTemplates.new
created = templates.create(
  name: "order_confirmation", language: "en_US", category: "UTILITY",
  components: [{ type: :body, text: "Thanks, {{1}}!", example: ["Pablo"] }]
)
templates.find(template_id: created.id).status # => "PENDING"

Defined Under Namespace

Modules: Categories, Defaults, Edges, Example, ParameterFormats, Placeholders, Response, Statuses, ValueObject Classes: Button, Component, ComponentSet, LibraryTemplate, Template, TemplateError

Constant Summary

Constants included from ResponseHandling

ResponseHandling::MAX_ERROR_BODY

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(client: Client.new) ⇒ MessageTemplates

Returns a new instance of MessageTemplates.

Parameters:

  • client (Whatsapp::Client) (defaults to: Client.new)

    The WhatsApp client instance.



50
51
52
# File 'lib/ruby/whatsapp/message_templates.rb', line 50

def initialize(client: Client.new)
  @client = client
end

Instance Attribute Details

#clientWhatsapp::Client

Returns:



47
48
49
# File 'lib/ruby/whatsapp/message_templates.rb', line 47

def client
  @client
end

Instance Method Details

#create(**attrs) ⇒ Response::Created

Creates a template.

Validation happens before the request, so an invalid template costs nothing. The response status is usually PENDING — Meta reviews templates asynchronously and reports the outcome via the message_template_status_update webhook.

Parameters:

  • attrs (Hash)

    Forwarded to Template (name:, language:, category:, components:, and the optional fields).

Returns:

Raises:

  • (ActiveModel::ValidationError)

    if the template is invalid.

  • (TemplateError)

    if the request fails.



64
65
66
# File 'lib/ruby/whatsapp/message_templates.rb', line 64

def create(**attrs)
  created_from(edge_path(Edges::MESSAGE_TEMPLATES), Template.new(**attrs), action: "create template")
end

#create_from_library(**attrs) ⇒ Response::Created

Creates a template by cloning one of Meta's pre-written library templates.

Uses the same edge as #create but a different payload — no components, just the library template's name and the inputs that customise it. Library templates are pre-categorised and pre-reviewed, so the response is usually APPROVED immediately.

Parameters:

Returns:

Raises:

  • (ActiveModel::ValidationError)

    if the payload is invalid.

  • (TemplateError)

    if the request fails.



77
78
79
80
81
82
# File 'lib/ruby/whatsapp/message_templates.rb', line 77

def create_from_library(**attrs)
  created_from(
    edge_path(Edges::MESSAGE_TEMPLATES), LibraryTemplate.new(**attrs),
    action: "create template from library"
  )
end

#delete(name: nil, hsm_id: nil, hsm_ids: nil) ⇒ Boolean

Deletes templates.

Three mutually exclusive ways to address them, and the choice matters:

`name:` alone   — deletes **every language variant** with that name
`hsm_id:`       — one template; Meta's docs pass `name:` alongside it
`hsm_ids:`      — up to 100 templates, and cannot be mixed with the other two

Deleting an approved template blocks reuse of its name for 30 days, and messages already in flight get a 30-day delivery window under the PENDING_DELETION status. DISABLED templates cannot be deleted at all.

Parameters:

  • name (String, nil) (defaults to: nil)

    The template name.

  • hsm_id (String, nil) (defaults to: nil)

    A single template ID.

  • hsm_ids (Array<String>, nil) (defaults to: nil)

    Up to 100 template IDs.

Returns:

  • (Boolean)

    Whether the API reported success.

Raises:

  • (TemplateError)

    if the arguments are unusable, or the request fails.



184
185
186
187
188
189
190
# File 'lib/ruby/whatsapp/message_templates.rb', line 184

def delete(name: nil, hsm_id: nil, hsm_ids: nil)
  params = delete_params(name:, hsm_id:, hsm_ids:)

  response = client.connection.delete(edge_path(Edges::MESSAGE_TEMPLATES), params:)

  success?(handle_response!(response, error_class: TemplateError, action: "delete template"))
end

#find(template_id:, fields: nil) ⇒ Response::Node

Reads a single template by ID.

Parameters:

  • template_id (String)

    The template's numeric ID.

  • fields (Array<String>, String, nil) (defaults to: nil)

    Restrict the response to these fields.

Returns:

Raises:



122
123
124
125
126
127
128
129
130
131
132
# File 'lib/ruby/whatsapp/message_templates.rb', line 122

def find(template_id:, fields: nil)
  raise TemplateError, "template_id can't be blank" if blank_value?(template_id)

  response = client.connection.get(
    client.path_for(template_id), params: encode_filters(fields:)
  )

  Response::Node.deserialize(
    parse_json(handle_response!(response, error_class: TemplateError, action: "find template"))
  )
end

#list(**filters) ⇒ Response::Collection

Lists the account's templates.

Parameters:

  • filters (Hash)

    Any documented filter: name, name_or_content, content, language, category, status, quality_score, since, until, fields, limit, after, before. Array values are encoded for you.

Returns:

Raises:



109
110
111
112
113
114
115
# File 'lib/ruby/whatsapp/message_templates.rb', line 109

def list(**filters)
  response = client.connection.get(edge_path(Edges::MESSAGE_TEMPLATES), params: encode_filters(filters))

  Response::Collection.deserialize(
    parse_json(handle_response!(response, error_class: TemplateError, action: "list templates"))
  )
end

#update(template_id:, category: nil, components: nil, message_send_ttl_seconds: nil, parameter_format: ParameterFormats::POSITIONAL) ⇒ Boolean

Edits a template.

Only category, components and message_send_ttl_seconds are editable, and components is a full replacement — Meta has no way to patch one component. The edit goes to the template's own ID with POST; PUT and PATCH are not supported on this edge.

Two limits cannot be checked locally, so they surface as API errors: only APPROVED, REJECTED and PAUSED templates may be edited (see Whatsapp::MessageTemplates::Response::Node#editable?), and an approved template allows 10 edits per 30 days and 1 per 24 hours. Editing an approved template also re-submits it for review, though it keeps working meanwhile.

Parameters:

  • template_id (String)

    The template's numeric ID.

  • category (String, Symbol, nil) (defaults to: nil)

    Cannot be changed on an APPROVED template.

  • components (Array<Hash, Component::Base>, nil) (defaults to: nil)

    The full replacement set.

  • message_send_ttl_seconds (Integer, nil) (defaults to: nil)
  • parameter_format (String, Symbol) (defaults to: ParameterFormats::POSITIONAL)

    Used to build and validate components locally; not sent, since Meta does not list it as editable.

Returns:

  • (Boolean)

    Whether the API reported success.

Raises:

  • (TemplateError)

    if there is nothing to update, or the request fails.

  • (ActiveModel::ValidationError)

    if the replacement components are invalid.



155
156
157
158
159
160
161
162
163
164
165
# File 'lib/ruby/whatsapp/message_templates.rb', line 155

def update(template_id:, category: nil, components: nil, message_send_ttl_seconds: nil,
  parameter_format: ParameterFormats::POSITIONAL)
  raise TemplateError, "template_id can't be blank" if blank_value?(template_id)

  payload = update_payload(category:, components:, message_send_ttl_seconds:, parameter_format:)
  raise TemplateError, "nothing to update: pass category, components or message_send_ttl_seconds" if payload.empty?

  response = client.connection.post(client.path_for(template_id), json: payload)

  success?(handle_response!(response, error_class: TemplateError, action: "update template"))
end

#upsert(**attrs) ⇒ Response::Created

Creates or updates the same template across several languages in one call.

Matching is on (name, language): an existing pair is updated, a missing one is created. Primarily documented for authentication templates.

Parameters:

  • attrs (Hash)

    Forwarded to Template; must include languages:.

Returns:

Raises:

  • (TemplateError)

    if languages: is missing or the request fails.

  • (ActiveModel::ValidationError)

    if the template is invalid.



92
93
94
95
96
97
98
99
100
# File 'lib/ruby/whatsapp/message_templates.rb', line 92

def upsert(**attrs)
  if blank_value?(attrs[:languages])
    raise TemplateError, "#upsert requires `languages:` (an array of locale codes); use #create for a single one"
  end

  created_from(
    edge_path(Edges::UPSERT_MESSAGE_TEMPLATES), Template.new(**attrs), action: "upsert templates"
  )
end