<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vonage Developers</title>
    <description>The latest articles on DEV Community by Vonage Developers (vonagedev).</description>
    <link>https://dev.to/vonagedev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F378%2F555ac53a-0535-46ae-8d35-c875f44eb774.jpg</url>
      <title>DEV Community: Vonage Developers</title>
      <link>https://dev.to/vonagedev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vonagedev"/>
    <language>en</language>
    <item>
      <title>Seeking Validation: Data Validation in Python with Pydantic and Vonage Verify</title>
      <dc:creator>Liz Acosta</dc:creator>
      <pubDate>Thu, 06 Aug 2026 19:59:45 +0000</pubDate>
      <link>https://dev.to/vonagedev/seeking-validation-data-validation-in-python-with-pydantic-and-vonage-verify-33p6</link>
      <guid>https://dev.to/vonagedev/seeking-validation-data-validation-in-python-with-pydantic-and-vonage-verify-33p6</guid>
      <description>&lt;p&gt;&lt;em&gt;This blog post provides an introduction to Pydantic, the popular data validation library for Python. It includes a demonstration of the value Pydantic provides using the Vonage Verify API.&lt;/em&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is Duck-typing in Python?
&lt;/h3&gt;

&lt;p&gt;To understand why &lt;a href="https://pydantic.dev/docs/validation/latest/get-started/" rel="noopener noreferrer"&gt;Pydantic&lt;/a&gt; is such a useful library, it is important to first understand how typing works in Python. In programming, “typing” refers to systems of classifying and categorizing data. How data is typed determines how it can be acted upon – for instance, you can’t add the word “two” with the number 2.&lt;/p&gt;

&lt;p&gt;Python owes a lot of its success and popularity to its flexibility around typing. Unlike most compiled languages that require you to explicitly declare types, Python implements something called &lt;strong&gt;duck-typing&lt;/strong&gt;. Duck-typing is a dynamic type system that assumes that if an object “walks like a duck and quacks like a duck, then it must be a duck.”&lt;/p&gt;

&lt;p&gt;More specifically, &lt;a href="https://docs.python.org/3/glossary.html#term-duck-typing" rel="noopener noreferrer"&gt;according to the Python documentation&lt;/a&gt;, duck-typing is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“A programming style which does not look at an object’s type to determine if it has the right interface; instead, the method or attribute is simply called or used … By emphasizing interfaces rather than specific types, well-designed code improves its flexibility by allowing polymorphic substitution. Duck-typing avoids tests using &lt;code&gt;type()&lt;/code&gt; or &lt;code&gt;isinstance()&lt;/code&gt;.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In practice, an example of this is Python’s &lt;code&gt;len&lt;/code&gt; function. &lt;code&gt;len()&lt;/code&gt; returns “&lt;a href="https://docs.python.org/3/library/functions.html#len" rel="noopener noreferrer"&gt;the length (the number of items) of an object&lt;/a&gt;.” In the code below, observe how &lt;code&gt;len()&lt;/code&gt; successfully produces an output regardless of the type of object it is called with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;example_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello? World!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;example_1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;str&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="gp"&gt;
&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;example_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;example_2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;list&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="gp"&gt;
&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;example_3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;world&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;foo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bar&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;example_3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;dict&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="gp"&gt;
&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;example_1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;13&lt;/span&gt;                                 &lt;span class="c1"&gt;# 13 letters in "Hello? World!"
&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;example_2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;4&lt;/span&gt;                                  &lt;span class="c1"&gt;# 4 items in the list
&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;example_3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;2&lt;/span&gt;                                  &lt;span class="c1"&gt;# 2 key-value pairs in the dictionary
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In an example of dynamic typing that more likely represents what you might see in Python in the real world, the code below defines three different classes of dog breeds that can each &lt;code&gt;bark()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Pug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The pug goes arf arf!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LabradorRetriever&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The labrador retriever goes arf arf!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Wolfhound&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The wolfhound goes arf arf!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can instantiate one of each kind of dog breed and call &lt;code&gt;bark()&lt;/code&gt; on every one of them without error because they all possess the same &lt;em&gt;interface&lt;/em&gt;. Because of duck-typing, the following code runs successfully:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;Pug&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;LabradorRetriever&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;Wolfhound&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;pet&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;     &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bark&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;The&lt;/span&gt; &lt;span class="n"&gt;pug&lt;/span&gt; &lt;span class="n"&gt;goes&lt;/span&gt; &lt;span class="n"&gt;arf&lt;/span&gt; &lt;span class="n"&gt;arf&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;
&lt;span class="n"&gt;The&lt;/span&gt; &lt;span class="n"&gt;labrador&lt;/span&gt; &lt;span class="n"&gt;retriever&lt;/span&gt; &lt;span class="n"&gt;goes&lt;/span&gt; &lt;span class="n"&gt;arf&lt;/span&gt; &lt;span class="n"&gt;arf&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;
&lt;span class="n"&gt;The&lt;/span&gt; &lt;span class="n"&gt;wolfhound&lt;/span&gt; &lt;span class="n"&gt;goes&lt;/span&gt; &lt;span class="n"&gt;arf&lt;/span&gt; &lt;span class="n"&gt;arf&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pet&lt;/code&gt; can be of class &lt;code&gt;Pug&lt;/code&gt;, &lt;code&gt;LabradorRetriever&lt;/code&gt;, or &lt;code&gt;Wolfhound&lt;/code&gt; and Python will still call the &lt;code&gt;bark&lt;/code&gt; function without error.&lt;/p&gt;

&lt;p&gt;This can be convenient, and in many contexts, it's exactly what you want. For scripting, data science, and exploratory work, Python's dynamic typing is a feature, not a bug. Duck-typing lets you iterate quickly without the overhead of rigid type declarations. This is a big part of why Python has become the dominant language for AI and data science workflows.&lt;/p&gt;

&lt;p&gt;However, the calculus changes significantly in production backend code. A Flask or Django application with no declared types can introduce maintenance and debugging friction. With Python’s duck-typing, type mismatches surface as cryptic runtime errors rather than clear, early failures. The problem becomes even more acute when applications rely on specific types of data in order to run as intended, such as when working with APIs, processing configuration files, or handling user input. &lt;/p&gt;

&lt;p&gt;For instance, if you defined the following class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Sphynx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;meow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The sphynx goes meow meow!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then updated the example code to include an instance of &lt;code&gt;Sphynx&lt;/code&gt; in the list of &lt;code&gt;pets&lt;/code&gt; to iterate through, you will run into an error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;Pug&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;LabradorRetriever&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;Sphynx&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;pet&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;     &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bark&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;     

&lt;span class="n"&gt;The&lt;/span&gt; &lt;span class="n"&gt;pug&lt;/span&gt; &lt;span class="n"&gt;goes&lt;/span&gt; &lt;span class="n"&gt;arf&lt;/span&gt; &lt;span class="n"&gt;arf&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;
&lt;span class="n"&gt;The&lt;/span&gt; &lt;span class="n"&gt;labrador&lt;/span&gt; &lt;span class="n"&gt;retriever&lt;/span&gt; &lt;span class="n"&gt;goes&lt;/span&gt; &lt;span class="n"&gt;arf&lt;/span&gt; &lt;span class="n"&gt;arf&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;
&lt;span class="nc"&gt;Traceback &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;python-input-74&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bark&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;^^^^^^^^&lt;/span&gt;
&lt;span class="nb"&gt;AttributeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Sphynx&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt; &lt;span class="n"&gt;has&lt;/span&gt; &lt;span class="n"&gt;no&lt;/span&gt; &lt;span class="n"&gt;attribute&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;bark&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As this example illustrates, within certain contexts, the flexibility of duck-typing becomes a liability. For example, a wrong type passed to an API call might not fail until the request is already in flight, potentially costing you money on a chargeable call that was always destined to fail.&lt;/p&gt;

&lt;p&gt;One way to address some of the issues that arise with dynamic typing is with Python’s &lt;a href="https://docs.python.org/3/library/typing.html" rel="noopener noreferrer"&gt;type hints&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are Type Annotations?
&lt;/h2&gt;

&lt;p&gt;A type hint is a code annotation that “&lt;a href="https://docs.python.org/3/glossary.html#term-type-hint" rel="noopener noreferrer"&gt;specifies the expected type for a variable, a class attribute, or a function parameter or return value&lt;/a&gt;.” Therefore, a &lt;strong&gt;type annotation&lt;/strong&gt; refers to how type hints are used syntactically in Python.&lt;/p&gt;

&lt;p&gt;The following code is a basic example of using type annotation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Hello &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the type hint is &lt;code&gt;str&lt;/code&gt; and the type annotation is the &lt;code&gt;name: str&lt;/code&gt; and &lt;code&gt;-&amp;gt; str&lt;/code&gt; syntax. The type annotation tells us that the expected type of the parameter &lt;code&gt;name&lt;/code&gt; is a string and that the expected return type of the function &lt;code&gt;greeting&lt;/code&gt; is a string.&lt;/p&gt;

&lt;p&gt;Adding type annotations to the example &lt;code&gt;Pug&lt;/code&gt; class could look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Pug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The pug &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; goes arf arf!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if we update our &lt;code&gt;pets&lt;/code&gt; iteration code to include type annotation, it could look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_dogs_bark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Pug&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;LabradorRetriever&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Wolfhound&lt;/span&gt; &lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;pet&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bark&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 

&lt;span class="nf"&gt;make_dogs_bark&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nc"&gt;Pug&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;LabradorRetriever&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;Sphynx&lt;/span&gt;&lt;span class="p"&gt;()])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As the name suggests, these are merely type &lt;em&gt;hints&lt;/em&gt;. They help make the code more readable and maintainable, but they are not enforced by the Python interpreter. We could use an additional tool like &lt;a href="https://mypy.readthedocs.io/en/latest/getting_started.html" rel="noopener noreferrer"&gt;mypy&lt;/a&gt; to check the types and receive an error like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="n"&gt;has&lt;/span&gt; &lt;span class="n"&gt;incompatible&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sphynx&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Pug | LabradorRetriever | Wolfhound&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would have to be performed as an additional step – nothing is preventing this code from executing and generating an error at runtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  Seeking Validation
&lt;/h2&gt;

&lt;p&gt;To prevent errors at runtime – such as an API call with incorrect data – you could &lt;em&gt;validate&lt;/em&gt; the data in your request &lt;em&gt;before&lt;/em&gt; sending it. In the example code, we could define some sort of validation to ensure each item in the list &lt;code&gt;pets&lt;/code&gt; can &lt;code&gt;bark()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_dogs_bark_safely&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dogs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Manual validation in the function&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;dog&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dogs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;bark&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;callable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;bark&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid dog type: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dog&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;dog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bark&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Now this fails immediately with a clear message:
&lt;/span&gt;&lt;span class="n"&gt;pets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;Pug&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;Sphynx&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;

&lt;span class="nf"&gt;make_dogs_bark_safely&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# TypeError: Invalid dog type: Sphynx
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition to quickly becoming tedious and unwieldy, this pattern undermines some of the conveniences of Python’s inherent dynamic-typing while also missing out on some of the benefits of type annotation.&lt;/p&gt;

&lt;p&gt;Fortunately, &lt;a href="https://pydantic.dev/docs/validation/latest/get-started/" rel="noopener noreferrer"&gt;Pydantic&lt;/a&gt; provides data validation while maintaining the ease and speed of the language using syntax already baked in.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Pydantic?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://pydantic.dev/docs/validation/latest/get-started/" rel="noopener noreferrer"&gt;Pydantic&lt;/a&gt; is a data validation library for Python offering the following benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Leverages &lt;a href="https://docs.python.org/3/glossary.html#term-type-hint" rel="noopener noreferrer"&gt;type hints&lt;/a&gt; to &lt;a href="https://pydantic.dev/docs/validation/latest/get-started/why#type-hints" rel="noopener noreferrer"&gt;control schema validation and serialization&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Uses &lt;a href="https://pydantic.dev/docs/validation/latest/get-started/why#performance" rel="noopener noreferrer"&gt;Rust under the hood&lt;/a&gt; for its core validation logic resulting in minimal impact on performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Supports &lt;a href="https://pydantic.dev/docs/validation/latest/get-started/why#dataclasses-typeddict-more" rel="noopener noreferrer"&gt;validation of many standard library types&lt;/a&gt; including &lt;code&gt;dataclass&lt;/code&gt; and &lt;code&gt;TypedDict&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Works in either &lt;a href="https://pydantic.dev/docs/validation/latest/get-started/why#strict-lax" rel="noopener noreferrer"&gt;strict or lax mode&lt;/a&gt; when handling types.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can output &lt;a href="https://json-schema.org/" rel="noopener noreferrer"&gt;JSON Schema&lt;/a&gt; out of the box, which enables seamless integration with other tools.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Automatically generates documentation from models.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s take a closer look at how these features come together in practice to provide reliable, efficient data validation in harmony with Python syntax and structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Validation Features of Pydantic
&lt;/h3&gt;

&lt;p&gt;It is important to understand that in Pydantic, “validation” refers to “&lt;a href="https://pydantic.dev/docs/validation/latest/concepts/models/" rel="noopener noreferrer"&gt;the process of instantiating a model (or other type) that adheres to specified types and constraints&lt;/a&gt;.” In other words, Pydantic’s validation applies to the output of a model instantiation, not the input data. As such, Pydantic raises a &lt;code&gt;ValidationError&lt;/code&gt; when data cannot be successfully parsed into an instance of a model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BaseModel&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;BaseModel&lt;/code&gt; lies at the heart of Pydantic. You inherit from it to define data models with type-annotated fields. One of the primary methods to define schema in Pydantic is via models. When you instantiate a &lt;code&gt;BaseModel&lt;/code&gt; Pydantic automatically validates the data against the defined schema.&lt;/p&gt;

&lt;p&gt;Using Pydantic, the &lt;code&gt;Pug&lt;/code&gt; class now looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Pug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fawn&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The pug &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; goes arf arf!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you were to instantiate &lt;code&gt;Pug&lt;/code&gt;, Pydantic would make sure the resulting object has a &lt;code&gt;name&lt;/code&gt; of type string, an &lt;code&gt;age&lt;/code&gt; of type integer, and a &lt;code&gt;color&lt;/code&gt; of type string with &lt;code&gt;fawn&lt;/code&gt; as the default.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Type Hints and Required Fields&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Type annotations control schema validation and serialization. Fields declared with just a type annotation are required; fields with defaults are optional.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;Pug&lt;/code&gt; example, the &lt;code&gt;name&lt;/code&gt; field is annotated with &lt;code&gt;str&lt;/code&gt; meaning any string will suffice, but a string &lt;em&gt;must&lt;/em&gt; be provided; the same applies to the &lt;code&gt;age&lt;/code&gt; field. The &lt;code&gt;color&lt;/code&gt; field, however,  provides a default of &lt;code&gt;fawn&lt;/code&gt; and thus not required when instantiating a &lt;code&gt;Pug&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Type Coercion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Pydantic can be used in either strict or the default lax mode. In lax mode, the library will automatically convert data to the type defined in the schema.&lt;/p&gt;

&lt;p&gt;So, for example, if we supplied &lt;code&gt;"5"&lt;/code&gt; as a string for the &lt;code&gt;age&lt;/code&gt; of a &lt;code&gt;Pug&lt;/code&gt;, Pydantic would convert it to an integer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Field Configuration
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;Field&lt;/code&gt; function enables the addition of metadata and constraints for schema fields.&lt;/p&gt;

&lt;p&gt;Some commonly used parameters are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Constraints&lt;/strong&gt; such as greater than &lt;code&gt;gt&lt;/code&gt;) and greater than or equal to &lt;code&gt;ge&lt;/code&gt;), and &lt;code&gt;min_length&lt;/code&gt; and &lt;code&gt;max_length&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Aliases&lt;/strong&gt; for mapping input and output field names using &lt;code&gt;alias&lt;/code&gt;, &lt;code&gt;validation_alias&lt;/code&gt;, and &lt;code&gt;serialization_alias&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Strict mode&lt;/strong&gt; to prevent type coercion on certain fields &lt;code&gt;strict=True&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To enforce constraints on the &lt;code&gt;name&lt;/code&gt; field for &lt;code&gt;Pug&lt;/code&gt;, you would use the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Pug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(...,&lt;/span&gt; &lt;span class="n"&gt;min_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The pug&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fawn&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The pug &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; goes arf arf!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Serialization
&lt;/h3&gt;

&lt;p&gt;Pydantic model instances can be converted to dictionaries without writing any additional serialization code by using &lt;code&gt;model_dump()&lt;/code&gt;. This makes it straightforward to serialize to JSON or other formats to use elsewhere in a project. For example, &lt;code&gt;model_dump_json()&lt;/code&gt; serializes a model directly to JSON.&lt;/p&gt;

&lt;p&gt;Below is an example of creating an instance of &lt;code&gt;Pug&lt;/code&gt; and then serializing it using one of Pydantic’s built-in functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;matty_pug&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Pug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Matty&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;matty_pug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_dump&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which would produce the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Matty&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;age&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;color&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fawn&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What is a Real-World Use Case of Pydantic?
&lt;/h2&gt;

&lt;p&gt;Since its inception, Pydantic has quickly become one of the most widely used data validation libraries for Python. Approximately 8,000 packages on PyPI use Pydantic including (and most famously) FastAPI, huggingface, Django Ninja, SQLModel, LangChain, and Vonage.&lt;/p&gt;

&lt;p&gt;In November 2024, Vonage &lt;a href="https://developer.vonage.com/en/blog/vonage-python-sdk-v4-is-now-live-" rel="noopener noreferrer"&gt;released a full, ground-up rewrite of the Vonage Python SDK&lt;/a&gt;. It’s not always easy to start over completely, but the rewrite was an opportunity to make some critical structural enhancements and improve user interaction with the SDK.&lt;/p&gt;

&lt;p&gt;Among some of the changes included in this initiative was the addition of Pydantic to the SDK in order to facilitate calling Vonage APIs and parsing the responses.&lt;/p&gt;

&lt;p&gt;Check out the video below to hear from one of our developers who works on the Python SDK and see what he has to say about using Pydantic.&lt;/p&gt;

&lt;h3&gt;
  
  
  How the Vonage Python SDK Uses Pydantic Models
&lt;/h3&gt;

&lt;p&gt;Using Pydantic models to form requests enforces correct typing and makes it easier to pass the right objects to the Vonage APIs. With version 4 of the SDK, API responses are now deserialized into fully documented Pydantic models, which provide more consistency than returning dictionaries like in the prior version. Additionally, you can still turn Pydantic models into dictionaries or JSON strings with &lt;code&gt;model.model_dump&lt;/code&gt; and &lt;code&gt;model.model_dump_json&lt;/code&gt; respectively.&lt;/p&gt;

&lt;p&gt;For this demonstration, we’ll take a look at the Vonage Verify API and how it is modeled using Pydantic in the SDK.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the Vonage Verify API?
&lt;/h3&gt;

&lt;p&gt;The Verify API is Vonage’s next generation two-factor authentication (2FA) product. With Verify API, you can authenticate your users and prevent fraud with a simple, easy-to-use API that abstracts away the complexity of 2FA at a global scale.&lt;/p&gt;

&lt;p&gt;It expands on traditional authentication methods by supporting a wider range of channels, including over-the-top (OTT) channels like WhatsApp, as well as SMS, voice, and email. The API supports both &lt;a href="https://developer.vonage.com/en/blog/using-jwt-for-authentication-in-a-golang-application-dr#jwt-introduction" rel="noopener noreferrer"&gt;JSON web tokens&lt;/a&gt; (JWT) and &lt;a href="https://developer.vonage.com/en/verify/concepts/authentication" rel="noopener noreferrer"&gt;Basic authentication&lt;/a&gt;. Basic authentication is easier to get started with, but does not support advanced features such as ACLs. You can use either JWT or Basic authentication, but not both at the same time. You can read more about authentication in the &lt;a href="https://developer.vonage.com/en/verify/concepts/authentication" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At a high level, the Verify API follows this workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An end-user triggers a 2FA request in an application&lt;/li&gt;
&lt;li&gt;On the backend, this 2FA request initiates a Verify API request &lt;/li&gt;
&lt;li&gt;The Verify API sends a one time password (OTP) to the end-user via the configured channel (SMS, voice, WhatsApp, or email)&lt;/li&gt;
&lt;li&gt;The end-user provides the OTP to the application&lt;/li&gt;
&lt;li&gt;This initiates a Verify request to check the OTP provided by the end-user against the OTP generated by the API&lt;/li&gt;
&lt;li&gt;The result of that check then determines what happens next (the end-user is authenticated, etc)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fa.storyblok.com%2Ff%2F270183%2F842x440%2F74fbe1e257%2Fverifyv2_request_summary_callbacks.png%2Fm%2Ffit-in" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fa.storyblok.com%2Ff%2F270183%2F842x440%2F74fbe1e257%2Fverifyv2_request_summary_callbacks.png%2Fm%2Ffit-in" alt="A diagram of the Verify V2 Request with Summary Callbacks." width="842" height="440"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A diagram of the Verify V2 Request with Summary Callbacks.&lt;/em&gt;&lt;br&gt;
A typical initially verification request includes the following payload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

   &lt;/span&gt;&lt;span class="nl"&gt;"locale"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"es-es"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"channel_timeout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"client_ref"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"myPersonalRef"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"code_length"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"e4dR1Qz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"brand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ACME"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"template_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4ed3027d-8762-44a0-aa3f-c393717413a4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"workflow"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"channel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sms"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"to"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"44770090000"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"channel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"voice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"to"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"44770090000"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which is explained more in-depth below:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Key&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Required or optional&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;locale&lt;/td&gt;
&lt;td&gt;The locale to use for the verification message&lt;/td&gt;
&lt;td&gt;Optional, defaults to &lt;code&gt;en-us&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;channel_timeout&lt;/td&gt;
&lt;td&gt;The time in seconds to wait between attempts to deliver the verification code&lt;/td&gt;
&lt;td&gt;Optional, defaults to 180 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;client_ref&lt;/td&gt;
&lt;td&gt;A unique identifier for the verification request&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;code_length&lt;/td&gt;
&lt;td&gt;The length of the verification code to generate&lt;/td&gt;
&lt;td&gt;Optional, defaults to 4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;code&lt;/td&gt;
&lt;td&gt;An optional alphanumeric custom code to use, if you don't want Vonage to generate the code&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;brand&lt;/td&gt;
&lt;td&gt;The name of the company or service that is sending the verification request – this will appear in the body of the SMS or TTS message&lt;/td&gt;
&lt;td&gt;Required, maximum length of 16 characters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;template_id&lt;/td&gt;
&lt;td&gt;A custom template ID to use – works only when &lt;code&gt;channel&lt;/code&gt; is &lt;code&gt;sms&lt;/code&gt; or &lt;code&gt;rcs&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;workflow&lt;/td&gt;
&lt;td&gt;The list of channels to use in the verification workflow, used in the order they are listed&lt;/td&gt;
&lt;td&gt;Required, maximum length of 3 items&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;To learn more about the API and how it works, refer to the &lt;a href="https://developer.vonage.com/en/verify/overview?source=verify" rel="noopener noreferrer"&gt;Vonage Verify documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A successful request responds with a &lt;code&gt;202 OK&lt;/code&gt; to indicate that the verification request has been initiated. The response will also include a &lt;code&gt;request_id&lt;/code&gt; which is required to complete the verification process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"request_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"c11236f4-00bf-4b89-84ba-88b25df97315"&lt;/span&gt;&lt;span class="p"&gt;,}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the same time, Vonage sends an OTP to the end-user via the configured workflow, attempting each channel in the order in which they are defined.&lt;/p&gt;

&lt;p&gt;Once the end-user receives and provides the OTP to the application, another request to the Verify endpoint with the &lt;code&gt;request_id&lt;/code&gt; as a path parameter &lt;code&gt;https://api.nexmo.com/v2/verify/:request_id&lt;/code&gt;) and the OTP in the request body for the &lt;code&gt;code&lt;/code&gt; key.&lt;/p&gt;

&lt;p&gt;If the code provided matches the code generated and sent by Vonage, a &lt;code&gt;200 OK&lt;/code&gt; response is returned along with a &lt;code&gt;"status": "complete"&lt;/code&gt; .&lt;/p&gt;

&lt;h2&gt;
  
  
  Demonstration: How Does the Verify API Use Pydantic?
&lt;/h2&gt;

&lt;p&gt;The Vonage Python SDK facilitates implementing the Vonage APIs within a Python application. Introducing Pydantic to the SDK makes it even easier to use the APIs. With Pydantic, rather than discovering an error &lt;em&gt;after&lt;/em&gt; making an API call and incurring any charges, request models are validated &lt;em&gt;before&lt;/em&gt; execution without the need for additional code to do so.&lt;/p&gt;

&lt;p&gt;The demonstration for this blog post is a minimal 2FA application using the FastAPI framework. The end-user navigates to a web page where they enter their email address. Using the Verify API, the application then generates an OTP code which is sent to the end-user provided email address. The end-user provides that code to the application and if the Verify check is successful, the end-user is rewarded with an animated gif. &lt;/p&gt;

&lt;p&gt;If you want, you can go straight to &lt;a href="http://github.com/Vonage-Community/demo-verify-python-pydantic-example" rel="noopener noreferrer"&gt;the code and use the README to get it up and running&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The following code is where the Verify request is created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;   &lt;span class="n"&gt;verify_request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;VerifyRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;brand&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verify_brand_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="nc"&gt;EmailChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;channel_timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;code_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we step into the &lt;code&gt;VerifyRequest&lt;/code&gt; object, we find a Pydantic model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;VerifyRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;brand&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(...,&lt;/span&gt; &lt;span class="n"&gt;min_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="n"&gt;Union&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="n"&gt;SilentAuthChannel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;SmsChannel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;WhatsappChannel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;VoiceChannel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;EmailChannel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Locale&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="n"&gt;channel_timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ge&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;900&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;client_ref&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;min_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;code_length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ge&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;^[a-zA-Z0-9]{4,10}$&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@model_validator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;after&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check_silent_auth_first_if_present&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;SilentAuthChannel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;VerifyError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;If using Silent Authentication, it must be the first channel in the &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;workflow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; list.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The schema translates the API request into types using Python annotation and the &lt;code&gt;Field&lt;/code&gt; function to define constraints. The &lt;code&gt;workflow&lt;/code&gt; field defines a &lt;code&gt;Union&lt;/code&gt; type of other modeled types, demonstrating how types can be nested.&lt;/p&gt;

&lt;p&gt;Lastly, the &lt;code&gt;model_validator(mode='after')&lt;/code&gt; is a Pydantic decorator that provides additional configuration for how the &lt;code&gt;VerifyRequest&lt;/code&gt; model is to be validated. In this case, the &lt;code&gt;def check_silent_auth_first_if_present&lt;/code&gt; method is executed &lt;em&gt;after&lt;/em&gt; the &lt;code&gt;VerifyRequest&lt;/code&gt; model has been constructed to ensure that if &lt;code&gt;SilentAuthChannel&lt;/code&gt; is included in the workflow, it must be listed first.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verification By Email
&lt;/h3&gt;

&lt;p&gt;To complete this tutorial, you will need a &lt;a href="https://developer.vonage.com/sign-up" rel="noopener noreferrer"&gt;Vonage API account&lt;/a&gt;. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the &lt;a href="https://developer.vonage.com/en/blog/$%7BCUSTOMER_DASHBOARD_URL%7D" rel="noopener noreferrer"&gt;Vonage API Dashboard&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After generating and activating a virtual environment, and installing the required dependencies per the &lt;a href="https://github.com/Vonage-Community/demo-verify-python-pydantic-example" rel="noopener noreferrer"&gt;README&lt;/a&gt;, you can run the demonstration application with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="n"&gt;dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will spin up a web app on &lt;code&gt;http://127.0.0.1:8000&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fa.storyblok.com%2Ff%2F270183%2F1544x914%2Fbeec6f2a67%2F202606_pydantic-verify_screenshot_index.png%2Fm%2Ffit-in" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fa.storyblok.com%2Ff%2F270183%2F1544x914%2Fbeec6f2a67%2F202606_pydantic-verify_screenshot_index.png%2Fm%2Ffit-in" alt="A screenshot of the index page inviting the end-user to enter their email address to try out the Vonage Verify API." width="1544" height="914"&gt;&lt;/a&gt;&lt;/p&gt;
A screenshot of the index page inviting the end-user to enter their email address to try out the Vonage Verify API.



&lt;p&gt;Clicking on &lt;strong&gt;Submit verification code&lt;/strong&gt; triggers the Verify API workflow. You should be directed to a web page where you can enter the code sent to the email address you provided:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fa.storyblok.com%2Ff%2F270183%2F1544x984%2Fa75f916c08%2F202606_pydantic-verify_screenshot_send-code.png%2Fm%2Ffit-in" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fa.storyblok.com%2Ff%2F270183%2F1544x984%2Fa75f916c08%2F202606_pydantic-verify_screenshot_send-code.png%2Fm%2Ffit-in" alt="A screenshot of the verification page inviting the end-user to enter the code they received in their email." width="1544" height="984"&gt;&lt;/a&gt;&lt;/p&gt;
A screenshot of the verification page inviting the end-user to enter the code they received in their email.



&lt;p&gt;Entering the correct code here will direct you to a success page.&lt;/p&gt;

&lt;p&gt;Under the hood, the &lt;a href="https://github.com/Vonage-Community/demo-verify-python-pydantic-example/blob/main/main.py" rel="noopener noreferrer"&gt;code makes use of the Pydantic models in the SDK&lt;/a&gt; to ensure the Verify request is correctly formed and handled.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verification Without Validation: Testing Without Pydantic
&lt;/h3&gt;

&lt;p&gt;Now let’s take a look at how Pydantic facilitates the Verify API.&lt;/p&gt;

&lt;p&gt;In the following code, we have two functions that perform the same task: make a request to the &lt;code&gt;/verify&lt;/code&gt; endpoint. One of the functions creates the request body manually and the other one uses Pydantic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using a manually created request body:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;without_pydantic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request_payload&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="n"&gt;jwt_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;JwtClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;application_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vonage_application_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;private_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vonage_private_key_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;jwt_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jwt_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_application_jwt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;brand&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;request_payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;brand&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;workflow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;channel&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;request_payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;to_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;channel_timeout&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;request_payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;channel_timeout&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;code_length&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;request_payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;code_length&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.nexmo.com/v2/verify&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;jwt_token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Using Pydantic:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;with_pydantic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request_payload&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Vonage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;Auth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;application_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vonage_application_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;private_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vonage_private_key_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;verify_request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;VerifyRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;brand&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request_payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;brand&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;EmailChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request_payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;to_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])],&lt;/span&gt;
        &lt;span class="n"&gt;channel_timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request_payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;channel_timeout&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;code_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request_payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;code_length&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start_verification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;verify_request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;last_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;http_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_response&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;last_response&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code then uses &lt;code&gt;unittest&lt;/code&gt; to test the functions with &lt;code&gt;test_data&lt;/code&gt; that violates the API parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;   &lt;span class="n"&gt;test_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;brand&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12345&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;to_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;678910&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;channel_timeout&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sixty&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;code_length&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;five&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the tests with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="n"&gt;unittest&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the tests should result in two different outcomes: an error and a failure.&lt;/p&gt;

&lt;p&gt;The test for the function that uses Pydantic should return this error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;pydantic_core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_pydantic_core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ValidationError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;validation&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;EmailChannel&lt;/span&gt;
&lt;span class="n"&gt;to&lt;/span&gt;
  &lt;span class="n"&gt;Input&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;valid&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;string_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input_value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;678910&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;For&lt;/span&gt; &lt;span class="n"&gt;further&lt;/span&gt; &lt;span class="n"&gt;information&lt;/span&gt; &lt;span class="n"&gt;visit&lt;/span&gt; &lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pydantic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;2.13&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;string_type&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What’s important to note here is that the test &lt;em&gt;did not fail&lt;/em&gt; – instead it errored out because Pydantic caught an incorrect data type &lt;em&gt;before&lt;/em&gt; the request was made. Moreover, the error message itself provides useful information for debugging instead of a general type error message. Not only do we know that the data type provided did not meet the model requirements, we also know what the expected type is as well as the type that was passed in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;Input&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;valid&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;string_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input_value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;678910&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The test for the function &lt;em&gt;without&lt;/em&gt; Pydantic returns a failure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nb"&gt;AssertionError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;422&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;202&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Test&lt;/span&gt; &lt;span class="n"&gt;without&lt;/span&gt; &lt;span class="n"&gt;Pydantic&lt;/span&gt; &lt;span class="n"&gt;failed&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;422.&lt;/span&gt; &lt;span class="n"&gt;Expected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;202&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means that the request was made and, as &lt;a href="https://developer.vonage.com/en/api/verify.v2?source=verify#newRequest-responses" rel="noopener noreferrer"&gt;the API is defined&lt;/a&gt;, returned a &lt;code&gt;422&lt;/code&gt; for invalid parameters. &lt;/p&gt;

&lt;p&gt;In this limited test scenario, one bad API call is negligible – on a broader scale, this can be an expensive mistake. Using Pydantic to validate a request model before making the API call helps minimize wasted API calls, enables more graceful error handling, and facilitates developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  In Summary
&lt;/h2&gt;

&lt;p&gt;Pydantic offers a powerful, performant solution for data validation in Python, helping developers move beyond the potential pitfalls of duck-typing. By defining schema, constraints, and validation rules with Pydantic models, you can ensure data integrity and catch errors before API requests are ever sent. This saves you from costly invalid API calls and makes error handling more graceful.&lt;/p&gt;

&lt;p&gt;As demonstrated with the Vonage Python SDK's integration with the Verify API, Pydantic makes it straightforward to work with complex, nested request models while keeping your code readable and maintainable. With version 4 of the SDK, API responses are deserialized into fully documented Pydantic models, giving you more consistency, better tooling support, and a cleaner developer experience overall.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading and References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.vonage.com/en/blog/silent-authentication-updates-in-verify-api" rel="noopener noreferrer"&gt;Silent Authentication Updates in Verify API&lt;/a&gt;: New Silent Authentication updates in Verify API improve dev/test experience.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.vonage.com/en/blog/build-passwordless-video-login-with-silent-auth-and-the-video-api" rel="noopener noreferrer"&gt;Build Passwordless Video Login with Silent Auth and the Video API&lt;/a&gt;: Use Silent Auth with Vonage Video to verify users automatically and start real-time sessions faster without passwords or codes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.vonage.com/en/blog/introducing-zero-tap-verification-for-whatsapp" rel="noopener noreferrer"&gt;Introducing Zero-Tap Verification for WhatsApp&lt;/a&gt;: Announcing the availability of Zero-tap verification for WhatsApp through the Vonage Verify v2 API.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Have a question or want to share what you're building? We invite you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Subscribe to the &lt;a href="https://developer.vonage.com/en/newsletter" rel="noopener noreferrer"&gt;Developer Newsletter&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  Follow us on &lt;a href="https://vonage.dev/TwitterBlog" rel="noopener noreferrer"&gt;X (formerly Twitter)&lt;/a&gt; for updates&lt;/li&gt;
&lt;li&gt;  Watch tutorials on our &lt;a href="https://vonage.dev/YouTubeBlog" rel="noopener noreferrer"&gt;YouTube channel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  Connect with us on the &lt;a href="https://vonage.dev/LinkedinBlog" rel="noopener noreferrer"&gt;Vonage Developer page on LinkedIn&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>fastapi</category>
      <category>pydantic</category>
    </item>
    <item>
      <title>The Vonage Dev Discussion: Everyone loves Pydantic</title>
      <dc:creator>Liz Acosta</dc:creator>
      <pubDate>Thu, 30 Jul 2026 18:03:50 +0000</pubDate>
      <link>https://dev.to/vonagedev/the-vonage-dev-discussion-everyone-loves-pydantic-32a7</link>
      <guid>https://dev.to/vonagedev/the-vonage-dev-discussion-everyone-loves-pydantic-32a7</guid>
      <description>&lt;p&gt;We’re back with another &lt;strong&gt;Vonage Dev Discussion&lt;/strong&gt;! &lt;/p&gt;

&lt;p&gt;If you’re a Python developer, chances are you’ve heard of &lt;strong&gt;&lt;a href="https://pydantic.dev/docs/validation/latest/get-started/" rel="noopener noreferrer"&gt;Pydantic&lt;/a&gt;&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Pydantic is a data validation library for Python. Since its release in 2017, Pydantic has quickly become one of the most popular dependencies in software, reaching &lt;strong&gt;&lt;em&gt;&lt;a href="https://pydantic.dev/articles/pydantic-validation-10-billion-downloads" rel="noopener noreferrer"&gt;10 billion downloads&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt; in 2026 🤯 &lt;/p&gt;

&lt;p&gt;But why is Pydantic so popular? We could name a few reasons – one of them being that it helped improve our Python SDK when we did a rewrite of it a couple of years ago.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/KuYbbHR37Dg?start=278"&gt;
  &lt;/iframe&gt;
 &lt;/p&gt;

&lt;p&gt;But what do you think? 🤔 &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why do you use Pydantic? What are some good use cases for it? How would you explain Pydantic to a beginner?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo9ce8d9pirh77pcmllu4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo9ce8d9pirh77pcmllu4.jpg" alt="A stylized illustration of a robot with a megaphone and a speech bubble with the following text: Why do you use Pydantic? What are some good use cases for it? How would you explain Pydantic to a beginner?" width="800" height="800"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;(By the way, if you’re totally new to Pydantic, we've got this &lt;a href="https://vonage.dev/4fx1yPe" rel="noopener noreferrer"&gt;gentle introduction&lt;/a&gt; to help you out!) &lt;/p&gt;

&lt;p&gt;Let us know your thoughts about Pydantic in the comments below! 🐍👇 &lt;/p&gt;

</description>
      <category>python</category>
      <category>pydantic</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Send Personalized SMS Messages from a Spreadsheet Using Claude Cowork and Vonage</title>
      <dc:creator>Michael Crump</dc:creator>
      <pubDate>Tue, 14 Jul 2026 19:25:48 +0000</pubDate>
      <link>https://dev.to/vonagedev/send-personalized-sms-messages-from-a-spreadsheet-using-claude-cowork-and-vonage-3b46</link>
      <guid>https://dev.to/vonagedev/send-personalized-sms-messages-from-a-spreadsheet-using-claude-cowork-and-vonage-3b46</guid>
      <description>&lt;p&gt;AI assistants are no longer just answering questions - they're taking action. Claude Cowork is a great example of this shift: it can access your local environment, read and write files, and automate tasks that would otherwise eat up your time. Pair it with the &lt;strong&gt;Vonage Tooling MCP Server&lt;/strong&gt;, and you can send real SMS messages to real people, all from a plain-English prompt.&lt;/p&gt;

&lt;p&gt;In this tutorial, we'll walk through exactly how to do that. We'll use Claude Cowork to read customer feedback from a local spreadsheet, generate personalized responses using AI, and automatically send each one as an SMS via Vonage.&lt;/p&gt;

&lt;p&gt;🎬 &lt;strong&gt;Watch the full video walkthrough here:&lt;/strong&gt; &lt;a href="https://www.youtube.com/watch?v=keMjIjOAkxk" rel="noopener noreferrer"&gt;Send a Text in Claude Cowork&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What You'll Build
&lt;/h2&gt;

&lt;p&gt;Imagine you run a restaurant. After each visit, customers text you their feedback, and you save their name, phone number, feedback, and a status column (&lt;code&gt;Pending&lt;/code&gt; / &lt;code&gt;Sent&lt;/code&gt;) in a spreadsheet called &lt;code&gt;restaurant_feedback.xlsx&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Using Claude Cowork, you'll create a task that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reads the spreadsheet and finds all rows with a &lt;code&gt;Pending&lt;/code&gt; status&lt;/li&gt;
&lt;li&gt;Uses AI to determine the sentiment of each message and generate a personalized response&lt;/li&gt;
&lt;li&gt;Sends each response as an SMS using the Vonage Tooling MCP Server&lt;/li&gt;
&lt;li&gt;Updates the status column to &lt;code&gt;Sent&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before you get started, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://claude.ai/download" rel="noopener noreferrer"&gt;Claude Desktop&lt;/a&gt; (latest version)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; installed&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://dashboard.vonage.com/" rel="noopener noreferrer"&gt;Vonage Developer account&lt;/a&gt; (free to sign up)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 1: Install the Vonage Tooling MCP Server
&lt;/h2&gt;

&lt;p&gt;Open Claude Desktop, click the &lt;strong&gt;Claude&lt;/strong&gt; menu in your computer's menu bar, then go to &lt;strong&gt;Settings → Developer → Edit Config&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This opens (or creates) a file called &lt;code&gt;claude_desktop_config.json&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;macOS:&lt;/strong&gt; &lt;code&gt;~/Library/Application Support/Claude/claude_desktop_config.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Windows:&lt;/strong&gt; &lt;code&gt;%APPDATA%\Claude\claude_desktop_config.json&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Paste in the following configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"vonage-mcp-server-api-bindings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"stdio"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"@vonage/vonage-mcp-server-api-bindings"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"VONAGE_APPLICATION_ID"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;YOUR_VONAGE_APPLICATION_ID&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"VONAGE_PRIVATE_KEY64"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;YOUR_VONAGE_PRIVATE_KEY64&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"VONAGE_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;YOUR_VONAGE_API_KEY&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"VONAGE_API_SECRET"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;YOUR_VONAGE_API_SECRET&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"VONAGE_VIRTUAL_NUMBER"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;YOUR_VONAGE_VIRTUAL_NUMBER&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"VONAGE_WHATSAPP_NUMBER"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;YOUR_VONAGE_WHATSAPP_NUMBER&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"RCS_SENDER_ID"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;YOUR_RCS_SENDER_ID&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 2: Get Your Vonage Credentials
&lt;/h2&gt;

&lt;p&gt;Log in to the &lt;a href="https://dashboard.vonage.com/" rel="noopener noreferrer"&gt;Vonage Developer Dashboard&lt;/a&gt; and grab the following:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;API Key &amp;amp; Secret&lt;/strong&gt;&lt;br&gt;
From your homepage, click &lt;strong&gt;API Secret Management&lt;/strong&gt; to copy your API key and secret.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Application ID &amp;amp; Private Key&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;Build → Applications → Create a new application&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Give it a name and click &lt;strong&gt;Generate public and private key&lt;/strong&gt; - the private key will download automatically&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Capabilities&lt;/strong&gt;, toggle on &lt;strong&gt;Messages&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Generate new application&lt;/strong&gt; to get your Application ID&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Before pasting the private key into the config file, you'll need to base64 encode it. Use the encoder linked in the &lt;a href="https://github.com/Vonage-Community/vonage-mcp-server-api-bindings" rel="noopener noreferrer"&gt;Vonage MCP Server readme&lt;/a&gt; or run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; private.key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Virtual Number&lt;/strong&gt;&lt;br&gt;
Go to &lt;strong&gt;Build → Phone Numbers&lt;/strong&gt; to find or purchase a virtual number. Link it to your application, and if you're in the US, make sure it's &lt;a href="https://developer.vonage.com/" rel="noopener noreferrer"&gt;10DLC compliant&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once your config is saved, &lt;strong&gt;restart Claude Desktop&lt;/strong&gt;. To confirm the server is connected, open a new chat and ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Do you have access to Vonage's tooling server?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Claude should confirm and list its available capabilities.&lt;/p&gt;


&lt;h2&gt;
  
  
  Step 3: Set Up Your Spreadsheet
&lt;/h2&gt;

&lt;p&gt;For this demo, create a file called &lt;code&gt;restaurant_feedback.xlsx&lt;/code&gt; in a folder called &lt;code&gt;operations&lt;/code&gt;. It should have columns for:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Phone&lt;/th&gt;
&lt;th&gt;Feedback&lt;/th&gt;
&lt;th&gt;Response&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Jane&lt;/td&gt;
&lt;td&gt;+1...&lt;/td&gt;
&lt;td&gt;"Great food!"&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;Pending&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bob&lt;/td&gt;
&lt;td&gt;+1...&lt;/td&gt;
&lt;td&gt;"Service was slow."&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;Pending&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;Status&lt;/code&gt; column is what Claude will use to know which messages need to be addressed.&lt;/p&gt;


&lt;h2&gt;
  
  
  Step 4: Create a &lt;code&gt;claude.md&lt;/code&gt; Instructions File
&lt;/h2&gt;

&lt;p&gt;To avoid re-prompting Claude every time, create a file called &lt;code&gt;claude.md&lt;/code&gt; in your &lt;code&gt;operations&lt;/code&gt; folder. This is a plain-text markdown file where you store persistent instructions for Claude Cowork.&lt;/p&gt;

&lt;p&gt;Here's an example of what to put in it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Restaurant Feedback Automation&lt;/span&gt;

When prompted with &lt;span class="sb"&gt;`generate_responses`&lt;/span&gt;:
&lt;span class="p"&gt;-&lt;/span&gt; Read &lt;span class="sb"&gt;`restaurant_feedback.xlsx`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Find all rows where Status = "Pending"
&lt;span class="p"&gt;-&lt;/span&gt; Analyze the sentiment of each feedback message
&lt;span class="p"&gt;-&lt;/span&gt; If positive: set Response to "We're glad you had a positive experience!"
&lt;span class="p"&gt;-&lt;/span&gt; If negative: set Response to "We're sorry you had a negative experience!"
&lt;span class="p"&gt;-&lt;/span&gt; Save the responses back to the spreadsheet

When prompted with &lt;span class="sb"&gt;`send_responses`&lt;/span&gt;:
&lt;span class="p"&gt;-&lt;/span&gt; Read &lt;span class="sb"&gt;`restaurant_feedback.xlsx`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; For each row where Status = "Pending" and a Response exists:
&lt;span class="p"&gt;  -&lt;/span&gt; Send the Response as an SMS to the customer's Phone number using the Vonage Tooling MCP Server
&lt;span class="p"&gt;  -&lt;/span&gt; Update the Status to "Sent"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 Tip: You can ask Claude itself to help you write your &lt;code&gt;claude.md&lt;/code&gt; file!&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 5: Run It in Claude Cowork
&lt;/h2&gt;

&lt;p&gt;Switch to &lt;strong&gt;Cowork mode&lt;/strong&gt; in Claude Desktop. Create a new task and click &lt;strong&gt;"Work in a project"&lt;/strong&gt; in the bottom-left corner of the prompt box. Select your &lt;code&gt;operations&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;Now run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;generate_responses
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude will scan the spreadsheet, find the &lt;code&gt;Pending&lt;/code&gt; rows, analyze sentiment, and write personalized responses back to the file.&lt;/p&gt;

&lt;p&gt;When you're ready to send, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;send_responses
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude will use the Vonage Tooling MCP Server to send each SMS and update the status to &lt;code&gt;Sent&lt;/code&gt;. Open your spreadsheet to confirm - the status column should now show &lt;code&gt;Sent&lt;/code&gt; for each row.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;This is just the beginning of what you can do with the Vonage Tooling MCP Server. Beyond SMS, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Send WhatsApp or RCS messages&lt;/strong&gt; by populating the corresponding fields in your config&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trigger automated voice calls&lt;/strong&gt; instead of (or in addition to) texts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Track delivery status&lt;/strong&gt; by saving read/delivered receipts back to your spreadsheet&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build multi-channel workflows&lt;/strong&gt; that escalate from SMS to voice if a message goes unread&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;📺 &lt;a href="https://www.youtube.com/watch?v=keMjIjOAkxk" rel="noopener noreferrer"&gt;Video: Send a Text in Claude Cowork&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📦 &lt;a href="https://github.com/Vonage-Community/vonage-mcp-server-api-bindings" rel="noopener noreferrer"&gt;Vonage Tooling MCP Server on GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📖 &lt;a href="https://modelcontextprotocol.io/docs/develop/connect-local-servers" rel="noopener noreferrer"&gt;Claude MCP Setup Docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🛠️ &lt;a href="https://dashboard.vonage.com/" rel="noopener noreferrer"&gt;Vonage Developer Dashboard&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📝 &lt;a href="https://developer.vonage.com/en/blog" rel="noopener noreferrer"&gt;Vonage Developer Blog&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Have questions or something cool you built with this? Drop a comment below or connect with us on the &lt;a href="https://developer.vonage.com/en/community/slack" rel="noopener noreferrer"&gt;Vonage Community Slack&lt;/a&gt;. We'd love to see what you create!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>vonage</category>
      <category>sms</category>
    </item>
    <item>
      <title>The Vonage Dev Discussion: How AI is transforming software development</title>
      <dc:creator>Liz Acosta</dc:creator>
      <pubDate>Thu, 21 May 2026 19:25:53 +0000</pubDate>
      <link>https://dev.to/vonagedev/the-vonage-dev-discussion-how-ai-is-transforming-software-development-1pof</link>
      <guid>https://dev.to/vonagedev/the-vonage-dev-discussion-how-ai-is-transforming-software-development-1pof</guid>
      <description>&lt;p&gt;Welcome back to the &lt;strong&gt;Vonage Dev Discussion&lt;/strong&gt;! Recently, members of the Vonage Developer Relations team met up in New York to create content, make plans, and hang out. We even got the chance to record at a super cool studio in the Big Apple!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fubkm67q08onq4i4foxwx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fubkm67q08onq4i4foxwx.jpg" alt="A photo of members from the Vonage Developer Relations team sitting in a recording studio." width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We took the opportunity to chat about something that’s been on everybody’s mind: artificial intelligence. We talked about how AI is impacting developer relations and tech in general.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/-d9XFWm86NM?start=880"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;We have a &lt;a href="https://vonage.dev/4wI4vCN" rel="noopener noreferrer"&gt;second part coming out soon&lt;/a&gt;, but in the meantime, we want to know: &lt;strong&gt;What’s one thing that AI helps you with? Where do you still prefer to do the work yourself?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgku7svth7dz5un215gf5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgku7svth7dz5un215gf5.png" alt="A stylized robot with the questions: What’s one thing that AI helps you with? Where do you still prefer to do the work yourself?" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We’d love to hear your thoughts in the comments below 🤖👇&lt;/p&gt;

</description>
      <category>ai</category>
      <category>discuss</category>
      <category>devrel</category>
    </item>
    <item>
      <title>The Vonage Dev Discussion: Defining what an API is</title>
      <dc:creator>Liz Acosta</dc:creator>
      <pubDate>Wed, 13 May 2026 20:49:48 +0000</pubDate>
      <link>https://dev.to/vonagedev/the-vonage-dev-discussion-defining-what-an-api-is-3806</link>
      <guid>https://dev.to/vonagedev/the-vonage-dev-discussion-defining-what-an-api-is-3806</guid>
      <description>&lt;p&gt;This week we kicked off the first in a series of office hours. Our office hours are a judgment-free space for developers to come and ask questions about using Vonage – and get an answer live from an actual human!&lt;/p&gt;

&lt;p&gt;Being able to ask questions without fear of judgment is so important for beginner engineers and being able to &lt;em&gt;answer&lt;/em&gt; those questions is equally important for senior engineers. Have you ever noticed how explaining something makes you &lt;em&gt;really think&lt;/em&gt; about what you actually know or don’t know? It's a really good feedback loop!&lt;/p&gt;

&lt;p&gt;So here’s a chance to test your knowledge: &lt;strong&gt;How would you explain what an API is to someone? What are some examples of APIs you use?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd0niycyz5pbvuiefxlb6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd0niycyz5pbvuiefxlb6.png" alt="A stylized robot with the questions: How would you explain what an API is to someone? What are some examples of APIs you use?" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And if you’re new to APIs, here’s a walkthrough of how to use one from our office hours:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/T5gPTyXGfOg?start=701"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;And don’t worry! If you run into any issues, we can help you out in our &lt;a href="https://vonage.dev/4uNHahr" rel="noopener noreferrer"&gt;next office hours&lt;/a&gt;. Check out the &lt;a href="https://vonage.dev/4uGRBmQ" rel="noopener noreferrer"&gt;office hours schedule&lt;/a&gt; and make sure to subscribe to our &lt;a href="https://www.youtube.com/@VonageDev/streams" rel="noopener noreferrer"&gt;YouTube channel&lt;/a&gt; for future streams and videos ♥️🤓&lt;/p&gt;

&lt;p&gt;Let's keep the API conversation going in the comments below! 💻 👇&lt;/p&gt;

</description>
      <category>vonage</category>
      <category>api</category>
      <category>discuss</category>
      <category>beginners</category>
    </item>
    <item>
      <title>The Vonage Dev Discussion: Making mistakes</title>
      <dc:creator>Liz Acosta</dc:creator>
      <pubDate>Fri, 24 Apr 2026 20:01:26 +0000</pubDate>
      <link>https://dev.to/vonagedev/the-vonage-dev-discussion-making-mistakes-32mc</link>
      <guid>https://dev.to/vonagedev/the-vonage-dev-discussion-making-mistakes-32mc</guid>
      <description>&lt;p&gt;Nobody is perfect! Even the most seasoned developers have made mistakes – it’s all just part of the learning process.&lt;/p&gt;

&lt;p&gt;One mistake that is so common in software development is accidentally pushing secrets to a public repository 🙈🙉🙊&lt;/p&gt;


&lt;div&gt;
    &lt;iframe src="https://www.youtube.com/embed/2bMfzLovLWM"&gt;
    &lt;/iframe&gt;
  &lt;/div&gt;


&lt;p&gt;Fortunately, there are lots of different guardrails you can put in place to help prevent the exposure of sensitive information like API keys, and we’ve covered a few of them in &lt;a href="https://vonage.dev/48R3sWS" rel="noopener noreferrer"&gt;these posts about environment variables&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But we’re curious: &lt;strong&gt;What are some mistakes you’ve made as a developer? What did you learn from those mistakes?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb9bjudjoqch6zqyh7vtd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb9bjudjoqch6zqyh7vtd.png" alt="A stylized illustration of the Vonage mascot with the text: What are some mistakes you’ve made as a developer? What did you learn from those mistakes?" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Share your wisdom in the comments below! 🙏👇&lt;/p&gt;

</description>
      <category>security</category>
      <category>discuss</category>
      <category>python</category>
    </item>
    <item>
      <title>The Vonage Dev Discussion: Builder pattern</title>
      <dc:creator>Liz Acosta</dc:creator>
      <pubDate>Tue, 07 Apr 2026 16:48:06 +0000</pubDate>
      <link>https://dev.to/vonagedev/the-vonage-dev-discussion-builder-pattern-1f45</link>
      <guid>https://dev.to/vonagedev/the-vonage-dev-discussion-builder-pattern-1f45</guid>
      <description>&lt;p&gt;Have you ever heard of the builder pattern? 🧰🏘️&lt;/p&gt;

&lt;p&gt;In software development, the builder pattern is a &lt;a href="https://vonage.dev/4c8VdpU" rel="noopener noreferrer"&gt;creational design pattern&lt;/a&gt; that lets you construct complex objects step by step. It is especially helpful when you have complex classes of objects that can be extended in many different ways.&lt;/p&gt;

&lt;p&gt;In this video, our developer advocates Guillaume Faas and Jeremy Foster discuss the builder pattern and how it is implemented in the &lt;a href="https://github.com/vonage/vonage-dotnet-sdk" rel="noopener noreferrer"&gt;Vonage .NET SDK&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/h31xOHKJ7D8"&gt;
  &lt;/iframe&gt;
&lt;br&gt;
The builder pattern &lt;a href="https://dev.to/tr00d/why-i-use-and-abuse-the-builder-pattern-3lbm"&gt;sparks debate in the dev community&lt;/a&gt;. Some swear by it, others see it as over-engineering. We want to know: &lt;strong&gt;What's your take?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do you use the builder pattern?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you use it in your own work?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How would you explain it to someone?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu5gw4srnoxebb0ulget7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu5gw4srnoxebb0ulget7.png" alt="A graphic of the Vonage mascot with the text: Do you use the builder pattern? How do you use it in your own work? How would you explain it to someone?" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Share your experience and knowledge of the builder pattern in the comments below! &lt;/p&gt;

&lt;p&gt;⚒️👇&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>architecture</category>
      <category>discuss</category>
    </item>
    <item>
      <title>The Vonage Dev Discussion: Open source</title>
      <dc:creator>Liz Acosta</dc:creator>
      <pubDate>Wed, 25 Mar 2026 16:59:12 +0000</pubDate>
      <link>https://dev.to/vonagedev/the-vonage-dev-discussion-open-source-ipb</link>
      <guid>https://dev.to/vonagedev/the-vonage-dev-discussion-open-source-ipb</guid>
      <description>&lt;p&gt;At &lt;a href="https://vonage.dev/41y34Zf" rel="noopener noreferrer"&gt;Women+ in Open Source Day&lt;/a&gt;, I got to try my hand at making a contribution to &lt;a href="https://vonage.dev/4uOwPmf" rel="noopener noreferrer"&gt;Apache Spark&lt;/a&gt;. While I didn’t manage to clone and build the project within the allotted time, I did get to speak with one of the project’s key contributors, &lt;a href="https://vonage.dev/4rQF26G" rel="noopener noreferrer"&gt;Holden Karau&lt;/a&gt;, and was inspired by her encouragement for all sorts of people to get involved.&lt;/p&gt;

&lt;p&gt;Contributing to open source can be intimidating! And in the age of AI, contributors from diverse perspectives are even more important.&lt;/p&gt;

&lt;p&gt;So for our second ever Dev Discussion, we want to know: &lt;strong&gt;What is your advice for getting started contributing to open source projects?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9i3f701wd102z9xapcdx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9i3f701wd102z9xapcdx.png" alt="A graphic of a robot with a speech bubble that reads, " width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Share your advice in the comments below along with links to some of your favorite open source projects! 🖥️ 🎉👇&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>opensource</category>
      <category>womenintech</category>
    </item>
    <item>
      <title>MCP, n8n, Symfony: New tutorials to kickstart 2026 🚀</title>
      <dc:creator>Daniela Facchinetti</dc:creator>
      <pubDate>Fri, 20 Feb 2026 11:07:25 +0000</pubDate>
      <link>https://dev.to/vonagedev/mcp-n8n-symfony-new-tutorials-to-kickstart-2026-36nm</link>
      <guid>https://dev.to/vonagedev/mcp-n8n-symfony-new-tutorials-to-kickstart-2026-36nm</guid>
      <description>&lt;p&gt;Hello Developers!&lt;/p&gt;

&lt;p&gt;Let’s kick off the new year with a quick look at our Q4 2025 launches. Then get ready for two new releases: &lt;strong&gt;Identity Insights in GA&lt;/strong&gt; plus &lt;strong&gt;Silent Authentication Advanced in Verify API&lt;/strong&gt;. And don’t forget the fresh tutorials — including AI-powered WhatsApp agents, Symfony SMS to 2FA, phone number insights, and Network APIs — to help you build smarter and more securely.&lt;/p&gt;

&lt;p&gt;Check them out and start building something amazing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RELEASES and ANNOUNCEMENTS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://developer.vonage.com/en/blog/vonage-q4-2025-recap-highlights-and-insights" rel="noopener noreferrer"&gt;Vonage Q4 2025 Recap: Highlights and Insights&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Last quarter doubled down on the fundamentals you count on every day. From stronger identity signals and AI-ready workflows to unified reporting and Video API improvements, the team shipped updates that make building easier and more reliable. Revisit how the updates help you build with confidence on Vonage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="//developer.vonage.com/en/blog/identity-insights-api-now-general-available"&gt;Identity Insights API Now Generally Available&lt;/a&gt;&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Your feedback was invaluable to refine real-time, production-ready phone number intelligence for identity verification, fraud prevention, and data enrichment. And now it’s all backed by enterprise-grade support.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://developer.vonage.com/en/blog/introducing-silent-authentication-advanced-in-the-verify-api" rel="noopener noreferrer"&gt;Introducing Silent Authentication Advanced in the Verify API&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The next evolution of authentication brings seamless, device-based verification beyond cellular networks to Wi-Fi and VPN. U.S. developers can be among the first to test this next-gen authentication flow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TUTORIALS and INSPIRATION&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://developer.vonage.com/en/blog/contribute-to-the-open-source-vonage-mcp-tooling-server" rel="noopener noreferrer"&gt;Contribute to the Open Source Vonage MCP Tooling Server&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Vonage MCP Tooling Server lets you power AI agents across messaging and voice channels. Tap into the open-source design to add new capabilities like MMS, SIM swap checks, or Voice API features.&lt;a href="https://developer.vonage.com/en/blog/authors/benjamin-aronov" rel="noopener noreferrer"&gt; Benjamin Aronov&lt;/a&gt; shows how to add a new tool and submit a Pull Request to help shape the future of the platform.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.youtube.com/watch?v=r134zNQO1tQ" rel="noopener noreferrer"&gt;What Are Network APIs?&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.vonage.com/en/blog/authors/jeremy-foster" rel="noopener noreferrer"&gt;Jeremy Foster&lt;/a&gt; provides a quick, developer-friendly intro to Vonage Network APIs. He also explains carrier-verified signals to help you verify identity, reduce fraud, and build trusted authentication experiences at scale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://developer.vonage.com/en/blog/eliminating-hallucinations-in-llm-driven-virtual-agents" rel="noopener noreferrer"&gt;Eliminating Hallucinations in LLM-Driven Virtual Agents&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Vonage AI Studio lets you build smart, low-code virtual agents. Recent updates improve LLM accuracy, stability, and reliability.&lt;a href="http://developer.vonage.com/en/blog/authors/shir-hilel" rel="noopener noreferrer"&gt; Shir Hilel&lt;/a&gt; shares insights and how these changes make conversations more predictable and grounded.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="//developer.vonage.com/en/blog/build-a-5-node-ai-whatsapp-receptionist-with-n8n-and-vonage-mcp-tools"&gt;Build a 5-Node AI WhatsApp Receptionist With n8n and Vonage MCP Tools&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.vonage.com/en/blog/authors/benjamin-aronov" rel="noopener noreferrer"&gt;Benjamin Aronov&lt;/a&gt; reviews the steps to automate guest support — such as managing routine questions, escalating urgent issues through SMS or voice, and keeping context with a simple, reusable workflow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://developer.vonage.com/en/blog/learn-about-phone-number-validity" rel="noopener noreferrer"&gt;Learn About Phone Number Validity &lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Accurate numbers are key for one-time passwords, updates, and support efficiency. Vonage Identity Insights API helps verify numbers across formats, carriers, and reachability checks.&lt;a href="https://developer.vonage.com/en/blog/authors/amanda-cavallaro" rel="noopener noreferrer"&gt; Amanda Cavallaro&lt;/a&gt; explains how ensuring number validity improves user experience and reduces errors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.youtube.com/watch?v=lHP943w_7Bk" rel="noopener noreferrer"&gt;Send SMS Text Message With Symfony&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Symfony keeps innovating in PHP, from API Platform to FrankenPHP. Curious about CPaaS? In this video, &lt;a href="https://developer.vonage.com/en/blog/authors/alexandra-williams" rel="noopener noreferrer"&gt;Alexandra Williams&lt;/a&gt; shows Symfony developers how to send an SMS with Vonage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="//developer.vonage.com/en/blog/how-to-add-two-factor-authentication-with-node-js-and-express"&gt;Add Two-Factor Authentication With Node.js, Express, and Vonage&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Two-factor authentication (2FA) adds an extra layer of security using a password plus a verification token. &lt;a href="https://developer.vonage.com/en/blog/authors/julia" rel="noopener noreferrer"&gt;Julia Biro&lt;/a&gt; demonstrates 2FA implementation with Vonage Verify API and Express.js.&lt;/p&gt;

</description>
      <category>vonagenews</category>
    </item>
    <item>
      <title>The Vonage Dev Discussion: Music</title>
      <dc:creator>Liz Acosta</dc:creator>
      <pubDate>Tue, 17 Feb 2026 20:50:55 +0000</pubDate>
      <link>https://dev.to/vonagedev/the-vonage-dev-discussion-4h52</link>
      <guid>https://dev.to/vonagedev/the-vonage-dev-discussion-4h52</guid>
      <description>&lt;p&gt;Hey developers! We want to hear from you for a series we’re calling the &lt;strong&gt;Dev Discussion&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;What is the Dev Discussion? We want it to be a space where we can take a break and talk about the human side of software development.&lt;/p&gt;

&lt;p&gt;Our first Dev Discussion topic is about &lt;strong&gt;music&lt;/strong&gt; 🎶&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcmfl6w1ljwabvanxnoas.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcmfl6w1ljwabvanxnoas.jpg" alt="A stylized illustration of a robot with the text: " width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Speaking of music and tech, you’ve probably heard &lt;a href="https://www.qobuz.com/ie-en/album/opus-no-1-tim-carleton-darrick-deel/vxcde5txl6b9a" rel="noopener noreferrer"&gt;this track&lt;/a&gt; while waiting on hold ☎️🎵&lt;/p&gt;

&lt;p&gt;Did you know it was composed in 1989 by Darrick Deel and Tim Carleton, a &lt;a href="https://www.thisamericanlife.org/516/stuck-in-the-middle-2014/act-one-0" rel="noopener noreferrer"&gt;self described&lt;/a&gt;, “Yanni-loving computer nerd” who was just “messing around with a drum machine and a synthesizer” in his parents' garage in California?&lt;/p&gt;

&lt;p&gt;You can &lt;a href="https://vonage.dev/46NixYz" rel="noopener noreferrer"&gt;make it your hold music too&lt;/a&gt;! &lt;/p&gt;

&lt;p&gt;Besides cool drum machines and chill synthesizers, we want to know:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is currently playing in your headphones?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does what you listen to change according to what you are working on?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do you ever work in complete silence?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Feel free to drop those playlists in the comments below 🎶 👇&lt;/p&gt;

</description>
      <category>music</category>
      <category>discuss</category>
      <category>api</category>
    </item>
    <item>
      <title>🎁 Holiday Update: MCP Tooling Server + LinkedIn Page</title>
      <dc:creator>Daniela Facchinetti</dc:creator>
      <pubDate>Fri, 09 Jan 2026 13:41:41 +0000</pubDate>
      <link>https://dev.to/vonagedev/holiday-update-mcp-tooling-server-linkedin-page-1iec</link>
      <guid>https://dev.to/vonagedev/holiday-update-mcp-tooling-server-linkedin-page-1iec</guid>
      <description>&lt;p&gt;Hi!&lt;/p&gt;

&lt;p&gt;An eventful 2025 closes with two big announcements: the introduction of the &lt;strong&gt;&lt;a href="https://github.com/Vonage-Community/vonage-mcp-server-api-bindings/tree/main" rel="noopener noreferrer"&gt;Vonage MCP Tooling Server&lt;/a&gt;&lt;/strong&gt; and the launch of the &lt;strong&gt;&lt;a href="http://vonage.dev/Linkedin" rel="noopener noreferrer"&gt;Vonage Developer LinkedIn Page&lt;/a&gt;&lt;/strong&gt;. Read on for more updates, fresh tutorials, and new ways to get the most out of Vonage APIs. &lt;/p&gt;

&lt;p&gt;Happy Holidays, and see you in the new year!&lt;/p&gt;

&lt;p&gt;Daniela, Developer Relations Content Manager&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RELEASES and ANNOUNCEMENTS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://developer.vonage.com/en/blog/introducing-the-vonage-mcp-tooling-server" rel="noopener noreferrer"&gt;Introducing the Vonage MCP Tooling Server&lt;/a&gt;&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Now, AI agents like Claude and Cursor can send messages, provision numbers, check balances, and manage your Vonage apps directly from a prompt. It’s open-source and secure, plus it comes with ready-to-use tools you can easily extend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://developer.vonage.com/en/blog/introducing-the-new-vonage-developer-linkedin-page" rel="noopener noreferrer"&gt;Introducing the Vonage Developer LinkedIn Page&lt;/a&gt;&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Here’s your space to stay up to date with insights and news, learn, connect with the community … not to mention participate in events, webinars, contests, and more. Make sure to follow us.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://developer.vonage.com/en/blog/announcing-ssl-security-enhancements" rel="noopener noreferrer"&gt;Announcing SSL Security Enhancements&lt;/a&gt;&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;These updates keep Vonage APIs securely encrypted and compatible with modern clients — and the benefits now extend to other Vonage domains. Learn how these SSL updates help protect your data and ensure secure end-to-end communications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TUTORIALS and INSPIRATION&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://developer.vonage.com/en/blog/spread-holiday-cheer-with-ai-agents-and-vonage-mcp-messaging-tools" rel="noopener noreferrer"&gt;Spread Holiday Cheer With AI Agents and Vonage MCP Messaging Tools&lt;/a&gt;&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;One-size-fits-all messaging no longer works. Some users prefer SMS, others like WhatsApp, and RCS adoption is growing fast.&lt;a href="https://developer.vonage.com/en/blog/authors/benjamin-aronov" rel="noopener noreferrer"&gt; Benjamin Aronov&lt;/a&gt; shows how to integrate an AI agent with the Vonage MCP Server to send holiday messages that automatically respect preferences, channels, and even language.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://developer.vonage.com/en/blog/monitor-your-webhooks-with-laravel-nightwatch" rel="noopener noreferrer"&gt;Monitor Your Webhooks With Laravel Nightwatch&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Monitoring PHP applications can be daunting. Laravel Nightwatch changes that with a native, easy-to-use way to track application events and performance.&lt;a href="https://developer.vonage.com/en/blog/authors/james-seconde" rel="noopener noreferrer"&gt; Jim Seconde&lt;/a&gt; spins up a simple webhook and monitors it all through the Nightwatch dashboard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.youtube.com/watch?v=LNH1cfTVcG8" rel="noopener noreferrer"&gt;Send and Receive WhatsApp Messages With Python&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.vonage.com/en/blog/authors/alexandra-williams" rel="noopener noreferrer"&gt;Alexandra Williams&lt;/a&gt; teaches you to use Flask to send and receive messages — without the full Vonage app or WhatsApp Business Account — making it the fastest way to experiment with Vonage Messages API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://developer.vonage.com/en/blog/improve-the-user-video-experience-with-real-time-quality-monitoring" rel="noopener noreferrer"&gt;Improve the User Video Experience With Real-Time Quality Monitoring &lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Did you know there’s a standard for how good your video looks and feels? The Mean Opinion Score (MOS) bridges the gap between technical metrics like jitter and latency with actual user satisfaction.&lt;a href="https://developer.vonage.com/en/blog/authors/amanda-cavallaro" rel="noopener noreferrer"&gt; Amanda Cavallaro&lt;/a&gt; explains MOS, why it’s subjective, and how your Vonage video application can use it to enhance user experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://developer.vonage.com/en/blog/identity-insights-api-use-cases-for-fraud-prevention" rel="noopener noreferrer"&gt;Identity Insights API Use Cases for Fraud Prevention &lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Fraud threats are evolving fast, with AI-driven scams targeting businesses of all sizes. Staying ahead requires smarter detection, stronger prevention, and constant vigilance.&lt;a href="https://developer.vonage.com/en/blog/authors/amanda-cavallaro" rel="noopener noreferrer"&gt; Amanda Cavallaro&lt;/a&gt; explores four identity insights use cases and how Vonage Identity Insights API provides real-time access to carrier, subscriber, and device data to help combat fraud.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EVENTS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://luma.com/347t02d7" rel="noopener noreferrer"&gt;Laravel Community Meetup&lt;/a&gt;&lt;/strong&gt; (London, 21 Jan.) &lt;/p&gt;

&lt;p&gt;The Vonage London office is hosting the next Laravel community meetup. Join us for an evening of networking, great talks, and friendly faces. Whether you’re a long-time member or brand new to the community, we’d love to see you there.&lt;/p&gt;

</description>
      <category>vonagenews</category>
    </item>
    <item>
      <title>Now live: U.S. Network APIs + Video API updates</title>
      <dc:creator>Daniela Facchinetti</dc:creator>
      <pubDate>Fri, 28 Nov 2025 17:19:10 +0000</pubDate>
      <link>https://dev.to/vonagedev/now-live-us-network-apis-video-api-updates-4fk0</link>
      <guid>https://dev.to/vonagedev/now-live-us-network-apis-video-api-updates-4fk0</guid>
      <description>&lt;p&gt;Hi!&lt;/p&gt;

&lt;p&gt;November brings exciting news: the launch of &lt;strong&gt;Network APIs in the U.S&lt;/strong&gt; and &lt;strong&gt;important Video API updates&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;As always, we bring you fresh tutorials to explore — including guides on &lt;strong&gt;RCS&lt;/strong&gt;, &lt;strong&gt;MCP&lt;/strong&gt;, and &lt;strong&gt;Laravel&lt;/strong&gt; — perfect for levelling up your developer skills. Stay tuned, dive in, and make the most of these updates to supercharge your projects. &lt;/p&gt;

&lt;p&gt;Best,&lt;/p&gt;

&lt;p&gt;Daniela - Developer Relations Content Manager @ Vonage&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RELEASES and ANNOUNCEMENTS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://developer.vonage.com/en/blog/vonage-launches-first-aggregated-network-apis-in-the-u-s-" rel="noopener noreferrer"&gt;Vonage Launches First Aggregated Network APIs in the U.S.&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Vonage brings aggregated Network API access for AT&amp;amp;T, T-Mobile, and Verizon. Developers can now tap into carrier-verified insights with a single integration to enable smarter, real-time identity, security, and connectivity features — minus individual carrier complexities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://developer.vonage.com/en/blog/vonage-reports-api-now-supports-video-api" rel="noopener noreferrer"&gt;Vonage Reports API Now Supports Video API&lt;/a&gt;&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Attention Unified Dashboard users — track all your Video, SMS, Messages, Voice, and Verify analytics in a single, easy-to-use interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://developer.vonage.com/en/blog/announcing-v1-3-0-of-the-vonage-video-reference-app-for-react" rel="noopener noreferrer"&gt;Announcing v1.3.0 of the Vonage Video Reference App for React&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The latest release introduces major UX upgrades, polished interfaces, and enhanced backend customization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://developer.vonage.com/en/blog/announcing-v2-32-0-of-the-vonage-video-api" rel="noopener noreferrer"&gt;Announcing v2.32.0 of the Vonage Video API&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You’ll enjoy advanced monitoring tools, finer video quality control across all major SDKs, and numerous stability and performance improvements, especially for web and iOS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TUTORIALS and INSPIRATION&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://developer.vonage.com/en/blog/step-by-step-adding-vonage-apis-to-your-ai-agent-with-mcp" rel="noopener noreferrer"&gt;Step-by-Step: Adding Vonage APIs to Your Agent With MCP&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.vonage.com/en/blog/authors/christankersley" rel="noopener noreferrer"&gt;Chris Tankerlsey&lt;/a&gt; guides you on how to create a chatbot using Anthropic Claude API and the Vonage Model Context Protocol (MCP) Tooling Server. So go ahead and chat, plus perform actions like checking account balances.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.youtube.com/watch?v=UOA1lLa9uLs" rel="noopener noreferrer"&gt;Introducing MCP: AI Meets Programmable Communications With Vonage&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AI agents can now handle tasks like “Send a text” with no code required. The Model Context Protocol (MCP) makes it possible by giving agents access to APIs and data across systems.&lt;a href="https://developer.vonage.com/en/blog/authors/alexandra-williams" rel="noopener noreferrer"&gt; Alexandra Williams&lt;/a&gt; details how Vonage is adopting this open standard with our newly launched Documentation MCP Server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://developer.vonage.com/en/blog/integrate-rcs-into-your-authentication-workflows" rel="noopener noreferrer"&gt;Integrate RCS Into Your Authentication Workflows&lt;/a&gt;&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;RCS brings SMS into the modern era with features like verified branding and read receipts.&lt;a href="https://developer.vonage.com/en/blog/authors/amanda-cavallaro" rel="noopener noreferrer"&gt; Amanda Cavallaro&lt;/a&gt; shows how to integrate RCS-based 2FA using Vonage Verify API, with automatic fallback to SMS when needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://developer.vonage.com/en/blog/sandbox-quickstart-send-and-receive-whatsapp-messages-with-python" rel="noopener noreferrer"&gt;Sandbox Quickstart: Send and Receive WhatsApp Messages With Python&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It’s time to test a chatbot, build a quick messaging prototype, and explore Vonage Messages API.&lt;a href="https://developer.vonage.com/en/blog/authors/benjamin-aronov" rel="noopener noreferrer"&gt; Benjamin Aronov&lt;/a&gt; shows you how to send and receive WhatsApp messages using Python and the Vonage WhatsApp Sandbox — with no need for a full app setup or WhatsApp Business Account (WABA).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://developer.vonage.com/en/blog/the-laravel-ai-experience-coding-basic-rcs-functionality" rel="noopener noreferrer"&gt;The Laravel AI Experience: Coding Basic RCS Functionality &lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AI is rapidly changing the developer experience, from tools like LaraCopilot to specialized MCP servers such as Laravel Boost.&lt;a href="https://developer.vonage.com/en/blog/authors/james-seconde" rel="noopener noreferrer"&gt; Jim Seconde&lt;/a&gt; explores how AI can help you prototype a Laravel app that sends and receives RCS messages, highlighting the new possibilities in PHP and Laravel development.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://developer.vonage.com/en/blog/laravel-12-starter-kits-explained-react-vue-and-livewire" rel="noopener noreferrer"&gt;Laravel 12 Starter Kits Explained: React, Vue, and Livewire&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The updated Laravel 12 starter kits simplify setup. Choose React, Vue, or Livewire to match your preferred workflow and get routes, controllers, and authentication ready out of the box.&lt;a href="https://developer.vonage.com/en/blog/authors/diana-pham" rel="noopener noreferrer"&gt; Diana Pham&lt;/a&gt; shows what each kit offers and how to find the best fit for your next Laravel app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EVENTS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://reinvent.awsevents.com/" rel="noopener noreferrer"&gt;AWS re:Invent&lt;/a&gt;&lt;/strong&gt;(Las Vegas, 1 to 5 Dec.)&lt;/p&gt;

&lt;p&gt;The Vonage Developer Ecosystem team is headed to Vegas. If your startup will be there, we’d love to connect. Book a meeting at: &lt;a href="mailto:startups@vonage.com"&gt;startups@vonage.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>vonagenews</category>
    </item>
  </channel>
</rss>
