diff --git a/examples/CONTENT_API.md b/examples/CONTENT_API.md new file mode 100644 index 000000000..e9470f551 --- /dev/null +++ b/examples/CONTENT_API.md @@ -0,0 +1,114 @@ +# Content API Examples + +This directory contains examples demonstrating how to use the Twilio Content API with the Ruby SDK. The Content API allows you to create and manage message templates with rich content types for various messaging channels. + +## Examples Overview + +### 1. `content_api_basic.rb` +Basic Content API examples showing the most common content types: +- **Text Content**: Simple text messages with variables +- **Media Content**: Text messages with attached images/videos +- **Location Content**: Location sharing with coordinates and labels +- **Quick Reply Content**: Messages with predefined quick reply buttons + +### 2. `content_api_advanced.rb` +Advanced Content API examples with more complex interactive content: +- **Call to Action Content**: Messages with action buttons (URL, phone number) +- **Card Content**: Rich card layout with title, subtitle, body, media, and actions +- **List Picker Content**: Interactive list selection menus +- **Carousel Content**: Horizontal scrolling cards +- **Catalog Content**: Product catalogs with pricing and descriptions + +### 3. `content_api_whatsapp.rb` +WhatsApp-specific Content API examples: +- **WhatsApp Authentication**: OTP and authentication message templates +- **WhatsApp Cards**: WhatsApp Business-specific card templates +- **WhatsApp Flows**: Interactive conversation flows for WhatsApp +- **Multi-language Templates**: Examples in multiple languages (English, Spanish, French) +- **Schedule Templates**: Appointment booking templates + +## Usage + +1. **Set your credentials**: Replace the placeholder values with your actual Twilio Account SID and Auth Token: + ```ruby + account_sid = 'ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' # Your Account SID + auth_token = 'your_auth_token' # Your Auth Token + ``` + +2. **Run the examples**: + ```bash + # Basic examples + ruby examples/content_api_basic.rb + + # Advanced examples + ruby examples/content_api_advanced.rb + + # WhatsApp examples + ruby examples/content_api_whatsapp.rb + ``` + +## Content Types Overview + +The Content API supports various content types, each with specific JSON payload structures: + +### Twilio Content Types +- **twilio/text**: Simple text messages +- **twilio/media**: Text with media attachments +- **twilio/location**: Location sharing +- **twilio/list-picker**: Interactive lists +- **twilio/call-to-action**: Action buttons +- **twilio/quick-reply**: Quick reply buttons +- **twilio/card**: Rich card layouts +- **twilio/catalog**: Product catalogs +- **twilio/carousel**: Card carousels +- **twilio/flows**: Conversation flows +- **twilio/schedule**: Appointment scheduling + +### WhatsApp Content Types +- **whatsapp/card**: WhatsApp Business cards +- **whatsapp/authentication**: Authentication templates + +## Key Concepts + +### Variables +Content templates support variables for personalization: +```ruby +"variables" => { + "1" => "customer_name", + "2" => "order_number" +} +``` + +Use `{{1}}`, `{{2}}`, etc. in your content to reference these variables. + +### Language Support +All templates require a language code: +```ruby +"language" => "en" # English +"language" => "es" # Spanish +"language" => "fr" # French +``` + +### Content Structure +Each content template requires: +- **friendly_name**: A descriptive name for the template +- **language**: Language code for the content +- **types**: The content type structure with specific fields +- **variables**: (Optional) Variable definitions for personalization + +## Error Handling + +The examples include basic error handling for common issues: +- Invalid credentials +- Missing required fields +- Malformed content structure +- API rate limits + +For production use, implement comprehensive error handling and validation. + +## Documentation + +For more information, see the official Twilio Content API documentation: +- [Content API Overview](https://www.twilio.com/docs/content) +- [Content API Reference](https://www.twilio.com/docs/content/api) +- [WhatsApp Templates](https://www.twilio.com/docs/whatsapp/api) \ No newline at end of file diff --git a/examples/content_api_advanced.rb b/examples/content_api_advanced.rb new file mode 100755 index 000000000..5ca94caf7 --- /dev/null +++ b/examples/content_api_advanced.rb @@ -0,0 +1,226 @@ +#!/usr/bin/env ruby + +# Add the lib directory to the load path for development +$LOAD_PATH.unshift File.expand_path('../lib', __FILE__) + +require 'twilio-ruby' + +# Your Account SID and Auth Token from console.twilio.com +account_sid = 'ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' +auth_token = 'your_auth_token' + +# Initialize the Twilio Client +@client = Twilio::REST::Client.new(account_sid, auth_token) + +puts "=== Advanced Content API Examples ===" + +# Example 1: Call to Action Content +puts "\n1. Creating Call to Action Content" +call_to_action_types = Twilio::REST::Content::V1::ContentList::Types.new({ + "twilio_call_to_action" => Twilio::REST::Content::V1::ContentList::TwilioCallToAction.new({ + "body" => "Ready to get started? Choose an option below:", + "actions" => [ + Twilio::REST::Content::V1::ContentList::CallToActionAction.new({ + "type" => "URL", + "title" => "Visit Website", + "url" => "https://www.example.com" + }), + Twilio::REST::Content::V1::ContentList::CallToActionAction.new({ + "type" => "PHONE_NUMBER", + "title" => "Call Us", + "phone" => "+1234567890" + }) + ] + }) +}) + +cta_request = Twilio::REST::Content::V1::ContentList::ContentCreateRequest.new({ + "friendly_name" => "Call to Action Template", + "language" => "en", + "types" => call_to_action_types +}) + +begin + cta_content = @client.content.v1.contents.create(content_create_request: cta_request) + puts "Call to action content created: #{cta_content.sid}" +rescue Twilio::REST::TwilioError => e + puts "Error creating call to action content: #{e.message}" +end + +# Example 2: Card Content +puts "\n2. Creating Card Content" +card_types = Twilio::REST::Content::V1::ContentList::Types.new({ + "twilio_card" => Twilio::REST::Content::V1::ContentList::TwilioCard.new({ + "title" => "{{1}}", + "subtitle" => "Special offer just for you!", + "body" => "Get {{2}}% off your next purchase. Limited time offer!", + "media" => "https://example.com/product-image.jpg", + "actions" => [ + Twilio::REST::Content::V1::ContentList::CardAction.new({ + "type" => "URL", + "title" => "Shop Now", + "url" => "https://example.com/shop" + }), + Twilio::REST::Content::V1::ContentList::CardAction.new({ + "type" => "PHONE_NUMBER", + "title" => "Call Store", + "phone" => "+1234567890" + }) + ] + }) +}) + +card_request = Twilio::REST::Content::V1::ContentList::ContentCreateRequest.new({ + "friendly_name" => "Product Card Template", + "language" => "en", + "variables" => { + "1" => "product_name", + "2" => "discount_percent" + }, + "types" => card_types +}) + +begin + card_content = @client.content.v1.contents.create(content_create_request: card_request) + puts "Card content created: #{card_content.sid}" +rescue Twilio::REST::TwilioError => e + puts "Error creating card content: #{e.message}" +end + +# Example 3: List Picker Content +puts "\n3. Creating List Picker Content" +list_picker_types = Twilio::REST::Content::V1::ContentList::Types.new({ + "twilio_list_picker" => Twilio::REST::Content::V1::ContentList::TwilioListPicker.new({ + "body" => "Please select a department:", + "button" => "Select Department", + "items" => [ + Twilio::REST::Content::V1::ContentList::ListItem.new({ + "id" => "sales", + "item" => "Sales Department", + "description" => "Questions about products and pricing" + }), + Twilio::REST::Content::V1::ContentList::ListItem.new({ + "id" => "support", + "item" => "Technical Support", + "description" => "Help with technical issues" + }), + Twilio::REST::Content::V1::ContentList::ListItem.new({ + "id" => "billing", + "item" => "Billing Department", + "description" => "Questions about your account and billing" + }) + ] + }) +}) + +list_picker_request = Twilio::REST::Content::V1::ContentList::ContentCreateRequest.new({ + "friendly_name" => "Department Selector Template", + "language" => "en", + "types" => list_picker_types +}) + +begin + list_picker_content = @client.content.v1.contents.create(content_create_request: list_picker_request) + puts "List picker content created: #{list_picker_content.sid}" +rescue Twilio::REST::TwilioError => e + puts "Error creating list picker content: #{e.message}" +end + +# Example 4: Carousel Content +puts "\n4. Creating Carousel Content" +carousel_types = Twilio::REST::Content::V1::ContentList::Types.new({ + "twilio_carousel" => Twilio::REST::Content::V1::ContentList::TwilioCarousel.new({ + "cards" => [ + Twilio::REST::Content::V1::ContentList::CarouselCard.new({ + "title" => "Product A", + "subtitle" => "Premium Quality", + "body" => "Our bestselling product with amazing features.", + "media" => "https://example.com/product-a.jpg", + "actions" => [ + Twilio::REST::Content::V1::ContentList::CarouselAction.new({ + "type" => "URL", + "title" => "View Details", + "url" => "https://example.com/product-a" + }) + ] + }), + Twilio::REST::Content::V1::ContentList::CarouselCard.new({ + "title" => "Product B", + "subtitle" => "Great Value", + "body" => "Affordable option without compromising quality.", + "media" => "https://example.com/product-b.jpg", + "actions" => [ + Twilio::REST::Content::V1::ContentList::CarouselAction.new({ + "type" => "URL", + "title" => "View Details", + "url" => "https://example.com/product-b" + }) + ] + }) + ] + }) +}) + +carousel_request = Twilio::REST::Content::V1::ContentList::ContentCreateRequest.new({ + "friendly_name" => "Product Carousel Template", + "language" => "en", + "types" => carousel_types +}) + +begin + carousel_content = @client.content.v1.contents.create(content_create_request: carousel_request) + puts "Carousel content created: #{carousel_content.sid}" +rescue Twilio::REST::TwilioError => e + puts "Error creating carousel content: #{e.message}" +end + +# Example 5: Catalog Content +puts "\n5. Creating Catalog Content" +catalog_types = Twilio::REST::Content::V1::ContentList::Types.new({ + "twilio_catalog" => Twilio::REST::Content::V1::ContentList::TwilioCatalog.new({ + "body" => "Browse our featured products:", + "items" => [ + Twilio::REST::Content::V1::ContentList::CatalogItem.new({ + "id" => "item1", + "section_title" => "Electronics", + "name" => "Smartphone", + "price" => 599.99, + "description" => "Latest model with advanced features", + "media_url" => "https://example.com/smartphone.jpg" + }), + Twilio::REST::Content::V1::ContentList::CatalogItem.new({ + "id" => "item2", + "section_title" => "Electronics", + "name" => "Laptop", + "price" => 999.99, + "description" => "High-performance laptop for professionals", + "media_url" => "https://example.com/laptop.jpg" + }) + ] + }) +}) + +catalog_request = Twilio::REST::Content::V1::ContentList::ContentCreateRequest.new({ + "friendly_name" => "Product Catalog Template", + "language" => "en", + "types" => catalog_types +}) + +begin + catalog_content = @client.content.v1.contents.create(content_create_request: catalog_request) + puts "Catalog content created: #{catalog_content.sid}" +rescue Twilio::REST::TwilioError => e + puts "Error creating catalog content: #{e.message}" +end + +puts "\n=== Content V2 API Example ===" +# Example using Content V2 API for listing +begin + v2_contents = @client.content.v2.contents.list(limit: 5) + puts "Found #{v2_contents.length} content templates using V2 API:" + v2_contents.each do |content| + puts "- #{content.friendly_name} (#{content.sid})" + end +rescue Twilio::REST::TwilioError => e + puts "Error listing V2 content: #{e.message}" +end \ No newline at end of file diff --git a/examples/content_api_basic.rb b/examples/content_api_basic.rb new file mode 100755 index 000000000..a88c20536 --- /dev/null +++ b/examples/content_api_basic.rb @@ -0,0 +1,140 @@ +#!/usr/bin/env ruby + +# Add the lib directory to the load path for development +$LOAD_PATH.unshift File.expand_path('../lib', __FILE__) + +require 'twilio-ruby' + +# Your Account SID and Auth Token from console.twilio.com +account_sid = 'ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' +auth_token = 'your_auth_token' + +# Initialize the Twilio Client +@client = Twilio::REST::Client.new(account_sid, auth_token) + +puts "=== Basic Content API Examples ===" + +# Example 1: Text Content +puts "\n1. Creating Text Content" +text_types = Twilio::REST::Content::V1::ContentList::Types.new({ + "twilio_text" => Twilio::REST::Content::V1::ContentList::TwilioText.new({ + "body" => "Hello {{1}}, this is a text message!" + }) +}) + +text_request = Twilio::REST::Content::V1::ContentList::ContentCreateRequest.new({ + "friendly_name" => "Text Message Template", + "language" => "en", + "variables" => { + "1" => "customer_name" + }, + "types" => text_types +}) + +begin + text_content = @client.content.v1.contents.create(content_create_request: text_request) + puts "Text content created: #{text_content.sid}" +rescue Twilio::REST::TwilioError => e + puts "Error creating text content: #{e.message}" +end + +# Example 2: Media Content (text + images/videos) +puts "\n2. Creating Media Content" +media_types = Twilio::REST::Content::V1::ContentList::Types.new({ + "twilio_media" => Twilio::REST::Content::V1::ContentList::TwilioMedia.new({ + "body" => "Check out this amazing offer {{1}}!", + "media" => [ + "https://example.com/image1.jpg", + "https://example.com/image2.jpg" + ] + }) +}) + +media_request = Twilio::REST::Content::V1::ContentList::ContentCreateRequest.new({ + "friendly_name" => "Media Message Template", + "language" => "en", + "variables" => { + "1" => "offer_details" + }, + "types" => media_types +}) + +begin + media_content = @client.content.v1.contents.create(content_create_request: media_request) + puts "Media content created: #{media_content.sid}" +rescue Twilio::REST::TwilioError => e + puts "Error creating media content: #{e.message}" +end + +# Example 3: Location Content +puts "\n3. Creating Location Content" +location_types = Twilio::REST::Content::V1::ContentList::Types.new({ + "twilio_location" => Twilio::REST::Content::V1::ContentList::TwilioLocation.new({ + "latitude" => 37.7749, + "longitude" => -122.4194, + "label" => "Twilio HQ", + "address" => "375 Beale St, San Francisco, CA 94105" + }) +}) + +location_request = Twilio::REST::Content::V1::ContentList::ContentCreateRequest.new({ + "friendly_name" => "Location Share Template", + "language" => "en", + "types" => location_types +}) + +begin + location_content = @client.content.v1.contents.create(content_create_request: location_request) + puts "Location content created: #{location_content.sid}" +rescue Twilio::REST::TwilioError => e + puts "Error creating location content: #{e.message}" +end + +# Example 4: Quick Reply Content +puts "\n4. Creating Quick Reply Content" +quick_reply_types = Twilio::REST::Content::V1::ContentList::Types.new({ + "twilio_quick_reply" => Twilio::REST::Content::V1::ContentList::TwilioQuickReply.new({ + "body" => "How can we help you today?", + "actions" => [ + Twilio::REST::Content::V1::ContentList::QuickReplyAction.new({ + "type" => "QUICK_REPLY", + "id" => "support", + "title" => "Get Support" + }), + Twilio::REST::Content::V1::ContentList::QuickReplyAction.new({ + "type" => "QUICK_REPLY", + "id" => "billing", + "title" => "Billing Questions" + }), + Twilio::REST::Content::V1::ContentList::QuickReplyAction.new({ + "type" => "QUICK_REPLY", + "id" => "sales", + "title" => "Talk to Sales" + }) + ] + }) +}) + +quick_reply_request = Twilio::REST::Content::V1::ContentList::ContentCreateRequest.new({ + "friendly_name" => "Quick Reply Menu Template", + "language" => "en", + "types" => quick_reply_types +}) + +begin + quick_reply_content = @client.content.v1.contents.create(content_create_request: quick_reply_request) + puts "Quick reply content created: #{quick_reply_content.sid}" +rescue Twilio::REST::TwilioError => e + puts "Error creating quick reply content: #{e.message}" +end + +puts "\n=== Listing Content Templates ===" +# List all content templates +begin + contents = @client.content.v1.contents.list(limit: 10) + contents.each do |content| + puts "Content: #{content.friendly_name} (#{content.sid}) - Language: #{content.language}" + end +rescue Twilio::REST::TwilioError => e + puts "Error listing content: #{e.message}" +end \ No newline at end of file diff --git a/examples/content_api_whatsapp.rb b/examples/content_api_whatsapp.rb new file mode 100755 index 000000000..b38e11b29 --- /dev/null +++ b/examples/content_api_whatsapp.rb @@ -0,0 +1,229 @@ +#!/usr/bin/env ruby + +# Add the lib directory to the load path for development +$LOAD_PATH.unshift File.expand_path('../lib', __FILE__) + +require 'twilio-ruby' + +# Your Account SID and Auth Token from console.twilio.com +account_sid = 'ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' +auth_token = 'your_auth_token' + +# Initialize the Twilio Client +@client = Twilio::REST::Client.new(account_sid, auth_token) + +puts "=== WhatsApp Content API Examples ===" + +# Example 1: WhatsApp Authentication Template +puts "\n1. Creating WhatsApp Authentication Content" +whatsapp_auth_types = Twilio::REST::Content::V1::ContentList::Types.new({ + "whatsapp_authentication" => Twilio::REST::Content::V1::ContentList::WhatsappAuthentication.new({ + "add_security_recommendation" => true, + "code_expiration_minutes" => 10, + "actions" => [ + Twilio::REST::Content::V1::ContentList::AuthenticationAction.new({ + "type" => "COPY_CODE", + "copy_code_text" => "Copy Code" + }) + ] + }) +}) + +whatsapp_auth_request = Twilio::REST::Content::V1::ContentList::ContentCreateRequest.new({ + "friendly_name" => "WhatsApp Authentication Template", + "language" => "en", + "types" => whatsapp_auth_types +}) + +begin + whatsapp_auth_content = @client.content.v1.contents.create(content_create_request: whatsapp_auth_request) + puts "WhatsApp authentication content created: #{whatsapp_auth_content.sid}" +rescue Twilio::REST::TwilioError => e + puts "Error creating WhatsApp auth content: #{e.message}" +end + +# Example 2: WhatsApp Card Template +puts "\n2. Creating WhatsApp Card Content" +whatsapp_card_types = Twilio::REST::Content::V1::ContentList::Types.new({ + "whatsapp_card" => Twilio::REST::Content::V1::ContentList::WhatsappCard.new({ + "header_text" => "Welcome to Our Service", + "body" => "Welcome to our WhatsApp Business! {{1}}", + "footer" => "Powered by Twilio", + "media" => ["https://example.com/whatsapp-header.jpg"], + "actions" => [ + Twilio::REST::Content::V1::ContentList::CardAction.new({ + "type" => "URL", + "title" => "Visit Website", + "url" => "https://www.example.com" + }), + Twilio::REST::Content::V1::ContentList::CardAction.new({ + "type" => "PHONE_NUMBER", + "title" => "Call Us", + "phone" => "+1234567890" + }) + ] + }) +}) + +whatsapp_card_request = Twilio::REST::Content::V1::ContentList::ContentCreateRequest.new({ + "friendly_name" => "WhatsApp Business Card Template", + "language" => "en", + "variables" => { + "1" => "customer_name" + }, + "types" => whatsapp_card_types +}) + +begin + whatsapp_card_content = @client.content.v1.contents.create(content_create_request: whatsapp_card_request) + puts "WhatsApp card content created: #{whatsapp_card_content.sid}" +rescue Twilio::REST::TwilioError => e + puts "Error creating WhatsApp card content: #{e.message}" +end + +# Example 3: WhatsApp Flows Template +puts "\n3. Creating WhatsApp Flows Content" +flows_types = Twilio::REST::Content::V1::ContentList::Types.new({ + "twilio_flows" => Twilio::REST::Content::V1::ContentList::TwilioFlows.new({ + "body" => "Start our interactive booking flow", + "button_text" => "Book Appointment", + "subtitle" => "Easy appointment scheduling", + "media_url" => "https://example.com/flows-preview.jpg", + "type" => "booking", + "pages" => [ + Twilio::REST::Content::V1::ContentList::FlowsPage.new({ + "id" => "page1", + "title" => "Select Service", + "subtitle" => "Choose the service you need", + "layout" => [ + Twilio::REST::Content::V1::ContentList::FlowsPageComponent.new({ + "type" => "dropdown", + "label" => "Service Type" + }) + ] + }), + Twilio::REST::Content::V1::ContentList::FlowsPage.new({ + "id" => "page2", + "title" => "Select Date & Time", + "subtitle" => "Pick your preferred slot", + "layout" => [ + Twilio::REST::Content::V1::ContentList::FlowsPageComponent.new({ + "type" => "date_picker", + "label" => "Appointment Date" + }), + Twilio::REST::Content::V1::ContentList::FlowsPageComponent.new({ + "type" => "time_picker", + "label" => "Appointment Time" + }) + ] + }) + ] + }) +}) + +flows_request = Twilio::REST::Content::V1::ContentList::ContentCreateRequest.new({ + "friendly_name" => "WhatsApp Booking Flow Template", + "language" => "en", + "types" => flows_types +}) + +begin + flows_content = @client.content.v1.contents.create(content_create_request: flows_request) + puts "WhatsApp flows content created: #{flows_content.sid}" +rescue Twilio::REST::TwilioError => e + puts "Error creating WhatsApp flows content: #{e.message}" +end + +# Example 4: Multi-language WhatsApp Template +puts "\n4. Creating Multi-language WhatsApp Content" +# Spanish version +spanish_types = Twilio::REST::Content::V1::ContentList::Types.new({ + "twilio_text" => Twilio::REST::Content::V1::ContentList::TwilioText.new({ + "body" => "¡Hola {{1}}! Gracias por contactarnos. ¿En qué podemos ayudarte hoy?" + }) +}) + +spanish_request = Twilio::REST::Content::V1::ContentList::ContentCreateRequest.new({ + "friendly_name" => "WhatsApp Greeting - Spanish", + "language" => "es", + "variables" => { + "1" => "customer_name" + }, + "types" => spanish_types +}) + +begin + spanish_content = @client.content.v1.contents.create(content_create_request: spanish_request) + puts "Spanish WhatsApp content created: #{spanish_content.sid}" +rescue Twilio::REST::TwilioError => e + puts "Error creating Spanish content: #{e.message}" +end + +# French version +french_types = Twilio::REST::Content::V1::ContentList::Types.new({ + "twilio_text" => Twilio::REST::Content::V1::ContentList::TwilioText.new({ + "body" => "Bonjour {{1}} ! Merci de nous avoir contactés. Comment pouvons-nous vous aider aujourd'hui ?" + }) +}) + +french_request = Twilio::REST::Content::V1::ContentList::ContentCreateRequest.new({ + "friendly_name" => "WhatsApp Greeting - French", + "language" => "fr", + "variables" => { + "1" => "customer_name" + }, + "types" => french_types +}) + +begin + french_content = @client.content.v1.contents.create(content_create_request: french_request) + puts "French WhatsApp content created: #{french_content.sid}" +rescue Twilio::REST::TwilioError => e + puts "Error creating French content: #{e.message}" +end + +# Example 5: Schedule/Appointment Template +puts "\n5. Creating WhatsApp Schedule Content" +schedule_types = Twilio::REST::Content::V1::ContentList::Types.new({ + "twilio_schedule" => Twilio::REST::Content::V1::ContentList::TwilioSchedule.new({ + "id" => "appointment_booking", + "title" => "Book your appointment with us!", + "time_slots" => "09:00-17:00" + }) +}) + +schedule_request = Twilio::REST::Content::V1::ContentList::ContentCreateRequest.new({ + "friendly_name" => "WhatsApp Appointment Scheduler", + "language" => "en", + "types" => schedule_types +}) + +begin + schedule_content = @client.content.v1.contents.create(content_create_request: schedule_request) + puts "Schedule content created: #{schedule_content.sid}" +rescue Twilio::REST::TwilioError => e + puts "Error creating schedule content: #{e.message}" +end + +puts "\n=== Filtering WhatsApp Content ===" +# Filter content by language and type +begin + whatsapp_contents = @client.content.v2.contents.list( + language: ['en', 'es', 'fr'], + limit: 20 + ) + + puts "WhatsApp content templates by language:" + languages = {} + whatsapp_contents.each do |content| + lang = content.language || 'unknown' + languages[lang] ||= 0 + languages[lang] += 1 + end + + languages.each do |lang, count| + puts "#{lang}: #{count} templates" + end +rescue Twilio::REST::TwilioError => e + puts "Error filtering content: #{e.message}" +end \ No newline at end of file