<?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: AbdulmalikAlayande</title>
    <description>The latest articles on DEV Community by AbdulmalikAlayande (@abdulmalikalayande).</description>
    <link>https://dev.to/abdulmalikalayande</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%2Fuser%2Fprofile_image%2F1190284%2Fee98b5f2-954a-4394-999c-abdc303ecaa2.jpeg</url>
      <title>DEV Community: AbdulmalikAlayande</title>
      <link>https://dev.to/abdulmalikalayande</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/abdulmalikalayande"/>
    <language>en</language>
    <item>
      <title>Realtime from First Principles, Part 2: WebSocket and The WebSocket Protocol</title>
      <dc:creator>AbdulmalikAlayande</dc:creator>
      <pubDate>Thu, 03 Sep 2026 19:40:06 +0000</pubDate>
      <link>https://dev.to/abdulmalikalayande/realtime-from-first-principles-part-2-websocket-and-the-websocket-protocol-2ddg</link>
      <guid>https://dev.to/abdulmalikalayande/realtime-from-first-principles-part-2-websocket-and-the-websocket-protocol-2ddg</guid>
      <description>&lt;p&gt;WebSocket is a communication protocol that enables full-duplex, bi-directional communication between a client and a server over a single, persistent connection built on top of TCP. Unlike the request-response model that defines regular HTTP traffic, where the client must always initiate every exchange and the server can only reply when asked, WebSocket keeps the connection open once it is established, so either side, the client or the server, can send data to the other at any moment, without waiting for a request first.&lt;/p&gt;

&lt;p&gt;Before going further, it helps to be clear on what full-duplex actually means, since it is easiest to understand next to its two relatives: simplex and half-duplex. All three describe the direction data is allowed to flow between two devices that are communicating with each other.&lt;/p&gt;

&lt;p&gt;Simplex communication only allows data to move in one direction, from a sender to a receiver, and never the other way. Think of a keyboard or a mouse sending input to a computer. The keyboard tells the computer what key was pressed, but the computer never sends anything back to the keyboard through that same channel. Data flows one way, permanently.&lt;/p&gt;

&lt;p&gt;Half-duplex communication allows data to move in both directions, but never at the same time. Only one side can send at any given moment, and the other side has to wait its turn. A walkie-talkie conversation is the clearest everyday example of this. When one person is speaking, the other person has to stay quiet and listen, and only after the first person finishes and signals that they are done, usually by saying something like "over," can the second person start talking. Both sides can send and receive, but taking turns is mandatory.&lt;/p&gt;

&lt;p&gt;Full-duplex communication allows data to move in both directions at the same time, with neither side needing to wait for the other. A regular phone call is the clearest example of this. Both people on the call can speak and listen at once, and if you interrupt the other person mid-sentence, they still hear you, because both directions of the conversation are open simultaneously. This is exactly the behavior WebSocket gives to a client and a server. Once the connection is open, the server does not have to wait for the client to ask before sending data, and the client does not have to wait for the server to finish before sending its own message. Both sides can talk over the same open connection whenever they need to.&lt;/p&gt;

&lt;p&gt;WebSocket came about as a direct answer to the limitations already discussed with HTTP-based workarounds like polling, long polling, and HTTP streaming in the &lt;a href="https://dev.to/abdulmalikalayande/realtime-from-first-principles-2nlp/"&gt;first series&lt;/a&gt;. The design intent was to give developers something closer to raw TCP itself, a connection where data can flow freely in both directions with minimal overhead. At the same time, they could not hand developers pure, unmodified TCP, because TCP on its own knows nothing about how the web works. It has no concept of an HTTP-based origin, no built-in way to distinguish one message from another, and no knowledge of the security assumptions browsers already rely on. So WebSocket layers a small number of abstractions on top of TCP, just enough to let it work correctly within the existing web platform, without reintroducing the request-response overhead it was designed to escape.&lt;/p&gt;

&lt;h3&gt;
  
  
  The WebSocket Protocol
&lt;/h3&gt;

&lt;p&gt;At a high level, the WebSocket protocol has three phases. It begins with an opening handshake, where a regular HTTP connection is upgraded into a WebSocket connection. This is followed by the data transfer phase, where the actual back-and-forth communication happens, with both the client and the server free to send messages whenever they need to, in either direction. Finally, there is a closing handshake, where either side signals that it wants to end the connection, and both sides agree to close it cleanly. Each of these phases is worth walking through in detail, starting with how the opening handshake actually works.&lt;/p&gt;

</description>
      <category>websocket</category>
      <category>realtime</category>
      <category>sse</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Realtime from First Principles, Part 1: How the Web Learned to Fake Realtime</title>
      <dc:creator>AbdulmalikAlayande</dc:creator>
      <pubDate>Tue, 25 Aug 2026 16:55:49 +0000</pubDate>
      <link>https://dev.to/abdulmalikalayande/realtime-from-first-principles-2nlp</link>
      <guid>https://dev.to/abdulmalikalayande/realtime-from-first-principles-2nlp</guid>
      <description>&lt;p&gt;During the 1990s, the web grew into the dominant way people exchange information, and browsers kept adding new features as more and more people got comfortable browsing. By the 2000s, the first attempts at realtime web apps started showing up, apps trying to feel responsive and interactive instead of the usual static webpage. But realtime was hard to pull off then, and slower than anything you would have recognize today, because it was being built by &lt;em&gt;hacking&lt;/em&gt; HTTP-based technologies that were never designed for that kind of work in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Origins of HTTP
&lt;/h2&gt;

&lt;p&gt;To understand why hacking HTTP-based technologies was even necessary, it helps to go back to where HTTP came from, In 1989, Tim Berners-Lee was working at CERN and grew frustrated with how hard it was to pull information off computers running different software from each other. Out of that frustration came a project called &lt;strong&gt;WorldWideWeb&lt;/strong&gt;: a web of hypertext documents that browsers could view over the internet using a client-server setup. That idea spread fast, and the first websites for everyday use appeared around 1993 to 1994.&lt;/p&gt;

&lt;p&gt;To build the web, Berners-Lee combined hypertext with the internet and produced three foundational pieces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTML: a markup language used to structure and present content on the web.&lt;/li&gt;
&lt;li&gt;URI: a unique address assigned to every resource on the web.&lt;/li&gt;
&lt;li&gt;HTTP: a way to request and receive resources on the web.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That very first version of HTTP, later called HTTP/0.9, was about as minimal as a protocol can get. A request was one line, starting with the only method that existed then, &lt;em&gt;GET&lt;/em&gt;, followed by a path. The response was raw hypertext, with no headers, status codes, or versioning, and the connection closed once the response was delivered.&lt;/p&gt;

&lt;p&gt;As interest in the web grew, browsers and servers started adding new features to the HTTP protocol, but a new problem began, new features added to the HTTP protocol was not coordinated, so there were different implementations of the HTTP/0.9, these implementations started drifting apart which led to the compatibility issues between different softwares that need to communicate with each other.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Rise of JavaScript
&lt;/h2&gt;

&lt;p&gt;While HTTP was maturing, something else was happening, &lt;em&gt;"The Browser Wars - browsers like Internet Explorer and Netscape Navigator working hard to out-feature each other"&lt;/em&gt;, it was in that competitive climate, in 1995, that Netscape hired Brendan Eich to add &lt;em&gt;scripting&lt;/em&gt; to Netscape Navigator, and &lt;em&gt;JavaScript&lt;/em&gt; was born. It started out doing almost nothing interesting, mostly basic form validation, but it was the first form of dynamism in a web that had until then been completely static. From there it kept getting standardized and adopted everywhere, eventually becoming one of the most important technologies of the web today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Early Attempts at Realtime
&lt;/h2&gt;

&lt;p&gt;With the existence of HTTP, HTML and now JavaScript, real web applications started to emerge, and the first serious attempts and efforts to make the web feel realtime came along in the late 90s. Two design models dominated that effort: &lt;em&gt;AJAX&lt;/em&gt; and &lt;em&gt;Comet&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  AJAX (Asynchronous JavaScript and XML)
&lt;/h3&gt;

&lt;p&gt;Ajax is a way of exchanging data with a server in the background and updating parts of a page without forcing a full reload. It was not a single technology on its own, it uses many existing technologies to achieve its realtime feel. It uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTML and CSS for the UI&lt;/li&gt;
&lt;li&gt;Document Object Model (DOM) for dynamic updates&lt;/li&gt;
&lt;li&gt;XML/JSON for the data format itself&lt;/li&gt;
&lt;li&gt;and most importantly the XMLHttpRequest object which allows JavaScript to make HTTP requests behind the scenes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ajax changed something structurally about how the classic web model worked. In the web model before AJAX, almost every user action fired off an HTTP request, and the server always sends back an entirely new HTML page in response. Ajax introduced something new between the server and the client - the AJAX engine. The client, instead of loading a fresh page each time it gets new contents, it loads the AJAX engine once and the engine takes over the job of polling the server in the background and asynchronously updating parts of the UI that needs updating.&lt;/p&gt;

&lt;h3&gt;
  
  
  Comet
&lt;/h3&gt;

&lt;p&gt;The comet model which came a bit later than AJAX, is a web application design model that allows the server to continuously push updates to the browser, Similar to Ajax, it asynchronously communicates with the browser, unlike Ajax, comet opens a long lived http connection that allows the server to continuously push updates to the client (browser), whenever they are available, without the client explicitly requesting them. Comet itself was also not a single technology, it was an umbrella covering a couple of approaches that are used to achieve the realtime feel. Comet uses two approaches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Long Polling: A smarter version of normal polling, where instead of the server replying immediately with "nothing yet" when there is no new data available, it holds the connection open for as long as required, until either new data actually shows up or a timeout hits and then the client immediately fires off another request to the server to keep the cycle going.&lt;/li&gt;
&lt;li&gt;HTTP Streaming (HTTP server push): A data transfer technique that allows a web server to continuously send data to a client over a single HTTP connection that remains open indefinitely. Whenever there's an update available, the server sends a response, and only closes the connection when explicitly told to do so. It is similar to Long Polling, just that it goes further still by keeping a single connection indefinitely.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Cost of Hacking HTTP
&lt;/h2&gt;

&lt;p&gt;By this point AJAX and Comet had already opened the door to dynamic, realtime-feeling web apps, and in a smaller way, both are still used today. But they were never solved the problem cleanly, because underneath all of it was still HTTP, and HTTP was built from the ground up to serve hypermedia resources in a request-response fashion: the client asks for something, the server responds, and that exchange is the complete transaction. It was never designed to handle high-frequency or ongoing client-server communication, or with the ability to react instantly to changes on either side. So, hacking HTTP-based technologies to emulate realtime web brought about different kinds of problems, and some of them are discussed below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Limited Scalability
&lt;/h3&gt;

&lt;p&gt;Take HTTP polling for example, which is sending requests to the server at fixed intervals to check whether new data is available. Polling very frequently means you get always get new data, but that comes with a problem, because high polling frequencies result in increased network traffic and server demands, which obviously does not scale well, especially as the number of concurrent users increases. Polling less frequently can reduce the network traffic and server demands, but that means handing the client information that has already gone stale by the time it arrives, which defeats the purpose of chasing realtime behavior in the first place.&lt;/p&gt;

&lt;p&gt;A better option would be Long Polling, but it also comes at its own cost because keeping thousands of "held-open" requests alive simultaneously demands a lot of server resources, since each one is still, at bottom, a connection the server has to maintain and eventually close and reopen.&lt;/p&gt;

&lt;h3&gt;
  
  
  Unreliable Message Ordering and Delivery Guarantee
&lt;/h3&gt;

&lt;p&gt;A client can have multiple requests in flight to the server at the same time, and because network conditions are unpredictable, there is no guarantee that requests will arrive at the server, or response will get to the client in the specific order they were sent. On top of that, a server might send a response that never reaches the client, whether due to a network hiccup or a browser issue, and unless the application has built some kind of receipt confirmation on top of HTTP itself, a message can simply vanish without either side realizing it.&lt;/p&gt;

&lt;h3&gt;
  
  
  No Bidirectional Streaming
&lt;/h3&gt;

&lt;p&gt;Another limitation of HTTP is that it does not have the concept of bidirectional streaming. It is a request/response protocol at its core, which means it was never built to let client and server hold an always-on, two-way conversation across a single connection. You can fake this by opening two separate HTTP connections, one for each direction, but now the server has to maintain double the connections to serve what is functionally one client, and that overhead compounds badly as your user count grows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Higher Latency
&lt;/h3&gt;

&lt;p&gt;Setting up a new HTTP connection requires a couple of handshakes involving several round-trips between the server and the client, before any useful data is sent, couple with the fact that HTTP requests are sequential by nature: the next request can only go out after the response to the current request is back. Network delays might also be a thing, depending on the network conditions at that moment. String enough of these together and the cumulative latency becomes a real problem for anything trying to feel instantaneous.&lt;/p&gt;

&lt;p&gt;A better option to avoid higher latency would be HTTP streaming techniques, since they avoid opening new connections repeatedly. But, they are still bound by the overhead of HTTP headers riding along with every message, resulting in increased message size and causing unnecessary delays. In many cases these headers end up outweighing the actual payload being delivered, which is a strange kind of inefficiency when the whole goal is speed.&lt;/p&gt;

&lt;p&gt;So every one of these techniques was, at its core, a workaround, and workarounds built on a mismatched foundation tend to produce their own new problems. That was the thread that leads into everything WebSocket was eventually built to fix.&lt;/p&gt;

&lt;p&gt;In the next series we will go fully into &lt;a href="https://dev.to/abdulmalikalayande/realtime-from-first-principles-part-2-websocket-and-the-websocket-protocol-2ddg"&gt;WebSocket&lt;/a&gt;&lt;/p&gt;

</description>
      <category>realtime</category>
      <category>websocket</category>
      <category>sse</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Building an RPC Server From Scratch in TypeScript</title>
      <dc:creator>AbdulmalikAlayande</dc:creator>
      <pubDate>Tue, 25 Aug 2026 16:44:56 +0000</pubDate>
      <link>https://dev.to/abdulmalikalayande/building-an-rpc-server-from-scratch-in-typescript-123i</link>
      <guid>https://dev.to/abdulmalikalayande/building-an-rpc-server-from-scratch-in-typescript-123i</guid>
      <description>&lt;h3&gt;
  
  
  Table of Contents
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;(Inter-Process Communication)[]&lt;/li&gt;
&lt;li&gt;(Remote Procedure Calls)[]&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rpc</category>
      <category>networking</category>
      <category>ipc</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Building an RPC Server From Scratch in TypeScript</title>
      <dc:creator>AbdulmalikAlayande</dc:creator>
      <pubDate>Tue, 25 Aug 2026 16:27:14 +0000</pubDate>
      <link>https://dev.to/abdulmalikalayande/building-an-rpc-server-from-scratch-in-typescript-alj</link>
      <guid>https://dev.to/abdulmalikalayande/building-an-rpc-server-from-scratch-in-typescript-alj</guid>
      <description>&lt;h3&gt;
  
  
  Table of Contents
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;(Inter-Process Communication)[]&lt;/li&gt;
&lt;li&gt;(Remote Procedure Calls)[]&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rpc</category>
      <category>networking</category>
      <category>ipc</category>
      <category>typescript</category>
    </item>
    <item>
      <title>OAUTH2.0 In Action — A Guide To Implementing OAUTH In Apps and Websites.</title>
      <dc:creator>AbdulmalikAlayande</dc:creator>
      <pubDate>Fri, 03 Jul 2026 12:44:56 +0000</pubDate>
      <link>https://dev.to/abdulmalikalayande/oauth20-in-action-a-guide-to-implementing-oauth-in-apps-and-websites-31h8</link>
      <guid>https://dev.to/abdulmalikalayande/oauth20-in-action-a-guide-to-implementing-oauth-in-apps-and-websites-31h8</guid>
      <description>&lt;h3&gt;
  
  
  Table of contents
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;What is OAUTH&lt;/li&gt;
&lt;li&gt;&lt;a href="//#a-trip-to-oauth1.0-ville"&gt;A trip to OAUTH1.0Ville&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="//#what-is-oauth2.0"&gt;What is OAUTH2.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Examples of OAUTH Technology&lt;/li&gt;
&lt;li&gt;OIDC&lt;/li&gt;
&lt;li&gt;Hands-on Implementation with Microsoft Entra ID&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What is OAUTH
&lt;/h2&gt;

&lt;p&gt;OAUTH is a technological standard that allows you to authorize one app or service to sign in to another without divulging private information, such as passwords.&lt;/p&gt;

&lt;p&gt;OAUTH stands for &lt;strong&gt;Open-Authorization&lt;/strong&gt;, not &lt;strong&gt;Authentication&lt;/strong&gt;. Authentication is a process that verifies your identity, although OAUTH involves identity verification, its main purpose is to grant access to connect you with different apps and services without requiring you to create a new account.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Does OAUTH Work
&lt;/h2&gt;

&lt;p&gt;OAUTH uses access tokens, and this is what makes OAUTH secure to use. An access token is a piece of data that contains information about the user and the resource the token is intended for. &lt;strong&gt;A token will also include specific rules for data sharing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example, you want to share your photos from Instagram with &lt;a href="https://kyrierapp.com" rel="noopener noreferrer"&gt;Kyrier — An intelligent email platform built for professionals who refuse to let their inbox run their day&lt;/a&gt;, but you only want Kyrier to access your profile image. Kyrier does not also need to access your direct messages or friends list. Instagram issues an access token to Kyrier to access the data you approve (your profile image in this case) on your behalf. So an access token will only allow Kyrier to access your profile image, not even other photos on your page. There may be rules governing when Kyrier can use the access token, it might be for a single use or for recurring uses, and it always has an expiration date.&lt;/p&gt;

&lt;h2&gt;
  
  
  A trip to OAUTH1.0Ville
&lt;/h2&gt;

&lt;p&gt;Welcome to OAuth1.0Ville. Please keep your hands inside the vehicle.&lt;/p&gt;

&lt;p&gt;This is where OAuth started. It was built &lt;strong&gt;only for websites&lt;/strong&gt;, back when "an app" meant a web page and nothing else. Although it  worked, it had a lot of problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only &lt;strong&gt;three authorization flows&lt;/strong&gt; (2.0 has six)&lt;/li&gt;
&lt;li&gt;No real plan for mobile or modern apps&lt;/li&gt;
&lt;li&gt;A scaling problem it never solved&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also makes you cryptographically sign &lt;strong&gt;every single request&lt;/strong&gt;, which does not sound like a problem until you are the one debugging why your signature does not match at 2am.&lt;/p&gt;

&lt;p&gt;Today almost nobody builds with OAuth1.0. OAuth2.0 is the new standard everyone uses and agrees with.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is OAUTH2.0
&lt;/h2&gt;

&lt;p&gt;OAuth 2.0 is the version you actually want. Think of it as OAuth 1.0 after it hit the gym, got a haircut, and stopped making your life difficult.&lt;/p&gt;

&lt;p&gt;It was a full redesign, not a patch. Several big tech companies threw in feedback, and the goal was simple: completely replace 1.0 and never speak of it again.&lt;/p&gt;

&lt;p&gt;Why everyone uses it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Works for &lt;strong&gt;both apps and websites&lt;/strong&gt;, not just websites&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster and easier&lt;/strong&gt; to implement&lt;/li&gt;
&lt;li&gt;Actually &lt;strong&gt;scales&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Gives you &lt;strong&gt;six authorization flows&lt;/strong&gt; to pick from, so the handshake fits what you are building (server app, mobile app, machine-to-machine, and so on)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You cannot upgrade OAuth 1.0 to 2.0. They are two different things. A site can technically support both, but that is like keeping a landline next to your smartphone.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Examples of OAUTH Technologies
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Say you are using Zoho Cliq as a collaboration tool, and you want to know more about the people you work with, both inside and outside your organization. So you enable integration with LinkedIn, so you can learn more about people as you interact with them, without ever leaving Zoho. LinkedIn uses OAUTH to authorize Zoho, so Zoho can pull the LinkedIn profile details you allow, right inside your Zoho workspace, without you handing over your LinkedIn password.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;As a developer, you are most certainly familiar with GitHub, or any other Software collaboration and code hosting tools like BitBucket or GitLab. Say you are using GitHub and You wanted to link CodeRabbit with your GitHub account so it can perform automated code reviews once you push or raise a PR, You go to GitHub through the CodeRabbit website and GitHub asks you to download the app, it would then ask you to authorize a connection with the app using your GitHub identity, a process that would be handled using OAUTH. CodeRabbit can then easily access the repositories you enabled it to access and starts listening for any PR or push events, and start reviewing your codes, without you having to sign in to both services every time. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  OIDC (Open ID Connect)
&lt;/h2&gt;

&lt;p&gt;OIDC is an authentication strategy to verify a person's identity, it is similar to OAUTH in that, they both give one application access to another application's resources on behalf of the user they are requesting for. Both OIDC and OAUTH have a role to play in enabling two unrelated apps to share information without compromising user data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hands-on Implementation with Microsoft Entra ID
&lt;/h2&gt;

&lt;p&gt;Enough of theory. Let us actually create up an app that can read someone's Outlook mailbox using OAuth 2.0. We will use &lt;strong&gt;delegated&lt;/strong&gt; access, meaning the app acts on behalf of a signed-in user, not as itself.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; All OAuth2 providers follow the &lt;strong&gt;same flow&lt;/strong&gt;: redirect the user to authorize, get a &lt;code&gt;code&lt;/code&gt; back, exchange that &lt;code&gt;code&lt;/code&gt; for tokens, fetch the user profile, then find or create the user and start a session.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Microsoft killed Basic Auth for Exchange Online back in October 2022, and EWS is on life support. In 2026, the only to authorize apps to access data on a users behalf using OAuth 2.0 is through Microsoft Graph, and that is what we will do now.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 1: Register your app in Microsoft Entra ID
&lt;/h3&gt;

&lt;p&gt;Go to the Microsoft Entra admin center (portal.azure.com), go to &lt;strong&gt;Microsoft Entra ID &amp;gt; App registrations &amp;gt; New registration&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Creating a new app normally is now impossible, you have to join the Microsoft 365 Developer Program &lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Give it a recognizable name (this is really important)&lt;/li&gt;
&lt;li&gt;Pick who can use it (single tenant is fine for now)&lt;/li&gt;
&lt;li&gt;Add a &lt;strong&gt;Redirect URI&lt;/strong&gt;. Pick &lt;strong&gt;Web&lt;/strong&gt; if it is a server-side app, or &lt;strong&gt;SPA&lt;/strong&gt; if it is a single-page app. Use something like &lt;code&gt;https://localhost/myapp/&lt;/code&gt; for local testing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click on register. On the &lt;strong&gt;Overview&lt;/strong&gt; page, copy two things you will need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Application (client) ID&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Directory (tenant) ID&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 2: Get a secret (or better, a certificate)
&lt;/h3&gt;

&lt;p&gt;Go to &lt;strong&gt;Certificates &amp;amp; secrets &amp;gt; New client secret&lt;/strong&gt;. Copy the &lt;strong&gt;Value&lt;/strong&gt; immediately. It is shown exactly once, then it is gone forever and you will be making a new one. Ask me how I know 😂.&lt;/p&gt;

&lt;p&gt;Note: certificates are more secure than secrets for production. For a hands-on demo like this, a secret is fine.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Add the permissions you need
&lt;/h3&gt;

&lt;p&gt;Go to &lt;strong&gt;API permissions &amp;gt; Add a permission &amp;gt; Microsoft Graph &amp;gt; Delegated permissions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For reading mail, add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;User.Read&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Mail.Read&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;offline_access&lt;/code&gt; (this is the one that gets you a refresh token, do not skip it)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only ask for what you need. The whole point of OAuth is that you do not grab the entire mailbox when you only want to read it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Send the user to log in (authorization request)
&lt;/h3&gt;

&lt;p&gt;Redirect the user to the authorize endpoint. This is the screen where they log in and approve your permissions:&lt;/p&gt;

</description>
      <category>oauth</category>
      <category>microsoft</category>
      <category>security</category>
      <category>oidc</category>
    </item>
    <item>
      <title>Nigerian Government Fees API: AI-Powered Public Service Data</title>
      <dc:creator>AbdulmalikAlayande</dc:creator>
      <pubDate>Mon, 15 Dec 2025 07:57:22 +0000</pubDate>
      <link>https://dev.to/abdulmalikalayande/nigerian-government-fees-api-ai-powered-public-service-data-3321</link>
      <guid>https://dev.to/abdulmalikalayande/nigerian-government-fees-api-ai-powered-public-service-data-3321</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/xanochallenge"&gt;Xano AI-Powered Backend Challenge&lt;/a&gt;: Production-Ready Public API&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I built the Nigerian Government and Public Utility Fees API, a production-ready REST API that provides verified, structured, and traceable information about Nigerian government fees and public utility costs and centralizes the information from multiple Nigerian agencies into one accessible endpoint.&lt;/p&gt;

&lt;p&gt;In Nigeria, citizens often struggle to find accurate information about the official cost of services such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;National Identification Number (NIN) services&lt;/li&gt;
&lt;li&gt;WAEC / NECO / JAMB examination fees&lt;/li&gt;
&lt;li&gt;Passport and identity-related processes&lt;/li&gt;
&lt;li&gt;Electricity tariffs across different DisCos&lt;/li&gt;
&lt;li&gt;Other government-regulated public fees&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For most Nigerians, finding accurate government fee information is frustrating. Information is usually scattered across PDFs, outdated websites, or unofficial sources. This API centralizes that data into a clean, developer-friendly backend that can be reliably consumed by applications, chatbots, dashboards, and AI agents.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Solution&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A single API that provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;90+ verified government fees across 6 categories (Identity, Immigration, Education, Electricity, Transport, Business)&lt;/li&gt;
&lt;li&gt;6 official agencies: NIMC, NIS, NECO, JAMB, NERC, UNILAG&lt;/li&gt;
&lt;li&gt;Complete documentation with code examples in JavaScript, Python, and cURL&lt;/li&gt;
&lt;li&gt;Rich relationship data: Every fee includes category, agency, and official source information&lt;/li&gt;
&lt;li&gt;Search &amp;amp; filtering: Find exactly what you need instantly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The API is built with a strong focus on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;official data sources&lt;/li&gt;
&lt;li&gt;traceability&lt;/li&gt;
&lt;li&gt;maintainability&lt;/li&gt;
&lt;li&gt;real-world production usage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Live API URL&lt;/strong&gt;: &lt;code&gt;https://xmlb-8xh6-ww1h.n7e.xano.io/api:public&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  API Documentation
&lt;/h2&gt;

&lt;p&gt;The API follows a simple and predictable REST structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Categories (e.g. Identity &amp;amp; Management, Education, Electricity)&lt;/li&gt;
&lt;li&gt;Subcategories (e.g. NIN, NECO, JAMB, Passport, DisCos)&lt;/li&gt;
&lt;li&gt;Fees (individual payable items)&lt;/li&gt;
&lt;li&gt;Agencies (government bodies)&lt;/li&gt;
&lt;li&gt;Sources (official documents and websites)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Base URL&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://xmlb-8xh6-ww1h.n7e.xano.io/api:public
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Authentication&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;API key via query parameter: &lt;code&gt;?api_key=YOUR_KEY&lt;/code&gt;&lt;br&gt;
Test API Key: &lt;code&gt;nga_b6cf98a60bda43ba8cf54af9dbd87260&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Available Endpoints&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  1. POST /api_key/generate
&lt;/h4&gt;

&lt;p&gt;Generates the API key to be used for accessing the secured endpoints.&lt;/p&gt;

&lt;p&gt;Example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; &lt;span class="s1"&gt;'POST''https://xmlb-8xh6-ww1h.n7e.xano.io/api:public/api_key/generate'&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{"user_email":"your-email@example.com"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2.  GET /fees
&lt;/h4&gt;

&lt;p&gt;Retrieve paginated list of fees with optional filtering.&lt;br&gt;
Parameters:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;category&lt;/code&gt; (optional) - Filter by category name/slug&lt;br&gt;
&lt;code&gt;state&lt;/code&gt; (optional) - Filter by state&lt;br&gt;
&lt;code&gt;search&lt;/code&gt; (optional) - Search in name and description&lt;br&gt;
&lt;code&gt;page&lt;/code&gt; (optional, default: 1) - Page number&lt;br&gt;
&lt;code&gt;per_page&lt;/code&gt; (optional, default: 20, max: 100) - Results per page&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s1"&gt;'https://xmlb-8xh6-ww1h.n7e.xano.io/api:public/fees?category=identity&amp;amp;per_page=5'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. GET /fees/{id}
&lt;/h4&gt;

&lt;p&gt;Get single fee by ID with all relationships.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s1"&gt;'https://xmlb-8xh6-ww1h.n7e.xano.io/api:public/fees/1?api_key=nga_b6cf98a60bda43ba8cf54af9dbd87260'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4. GET /fees/search
&lt;/h4&gt;

&lt;p&gt;Search fees by name and description (min 2 characters).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s1"&gt;'https://xmlb-8xh6-ww1h.n7e.xano.io/api:public/fees/search?q=passport&amp;amp;api_key=nga_b6cf98a60bda43ba8cf54af9dbd87260'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  5. GET /categories
&lt;/h4&gt;

&lt;p&gt;Get all categories with fee counts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s1"&gt;'https://xmlb-8xh6-ww1h.n7e.xano.io/api:public/categories?api_key=nga_b6cf98a60bda43ba8cf54af9dbd87260'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  6. GET /metadata
&lt;/h4&gt;

&lt;p&gt;Get API statistics and version information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s1"&gt;'https://xmlb-8xh6-ww1h.n7e.xano.io/api:public/metadata?api_key=nga_b6cf98a60bda43ba8cf54af9dbd87260'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rate Limits
&lt;/h3&gt;

&lt;p&gt;Currently no rate limits enforced. Request tracking is implemented for future rate limiting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Response Format
&lt;/h3&gt;

&lt;p&gt;All responses are JSON. Errors follow standardized format:&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;"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;"ERROR_CODE_TYPE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Human-readable error message"&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;&lt;strong&gt;Full documentation:&lt;/strong&gt; Available in my GitHub repository with complete request/response examples, error handling, and integration guides.&lt;/p&gt;




&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Example 1: Generate API Key
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Request:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; &lt;span class="s1"&gt;'POST''https://xmlb-8xh6-ww1h.n7e.xano.io/api:public/api_key/generate'&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{"user_email":"your-email@example.com"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Response:&lt;/strong&gt;&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;"success"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"api_key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"nga_********************************"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"API key generated successfully. Please save this key as it provides access to the API."&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;h3&gt;
  
  
  Example 2: Get All Categories
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Request:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; &lt;span class="s1"&gt;'GET'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'https://xmlb-8xh6-ww1h.n7e.xano.io/api:public/categories?api_key=nga_b6cf98a60bda43ba8cf54af9dbd87260'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'accept: application/json'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Response:&lt;/strong&gt;&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"display_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Identity &amp;amp; Management"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Fees related to national identity systems such as NIN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"fee_count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;19&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"display_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Immigration"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passport and visa related fees"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"fee_count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"display_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Education"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NECO, JAMB and related examination fees"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"fee_count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;45&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;h3&gt;
  
  
  Example 3: Search for NIN Fees
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Request:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; &lt;span class="s1"&gt;'GET'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'https://xmlb-8xh6-ww1h.n7e.xano.io/api:public/fees/search?q=NIN&amp;amp;api_key=nga_b6cf98a60bda43ba8cf54af9dbd87260'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'accept: application/json'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Response:&lt;/strong&gt;&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NIN Enrolment (First Time)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NGN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"service_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;"Standard"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Initial NIN enrollment is free"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"category_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Identity &amp;amp; Management"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"agency_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"National Identity Management Commission"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"subcategory_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NIN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"source_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NIMC"&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;h3&gt;
  
  
  Example 4: Get Fee Details
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Request:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; &lt;span class="s1"&gt;'GET'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'https://xmlb-8xh6-ww1h.n7e.xano.io/api:public/fees/20?api_key=nga_b6cf98a60bda43ba8cf54af9dbd87260'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'accept: application/json'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Response:&lt;/strong&gt;&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Standard Passport 32 Pages (5-Year Validity)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NGN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"service_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;"Standard"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"New or Renewal"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"subcategory"&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passport"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"category"&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Immigration"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passport and visa related fees"&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;"source"&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Nigerian Immigration Service (NIS)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"agency"&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Nigeria Immigration Service"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"website"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://immigration.gov.ng"&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;h3&gt;
  
  
  Code Integration Examples
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;JavaScript:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BASE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://xmlb-8xh6-ww1h.n7e.xano.io/api:public&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nga_b6cf98a60bda43ba8cf54af9dbd87260&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;searchFees&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;BASE_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/fees/search?q=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;api_key=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Found &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; fees matching "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;searchFees&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;passport&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Python:&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="n"&gt;BASE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://xmlb-8xh6-ww1h.n7e.xano.io/api:public&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;nga_b6cf98a60bda43ba8cf54af9dbd87260&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;search_fees&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&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;get&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="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;BASE_URL&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/fees/search&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;params&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;q&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;api_key&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;Found &lt;/span&gt;&lt;span class="si"&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;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; fees matching &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;query&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;

&lt;span class="nf"&gt;search_fees&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;passport&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;&lt;strong&gt;Try it yourself with your API key, see the example provided above!&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The AI Prompt I Used
&lt;/h2&gt;

&lt;p&gt;I used &lt;strong&gt;Cursor with XanoScript&lt;/strong&gt; to generate all 5 core endpoints. Here's my main prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Generate 5 Xano API endpoints for a Nigerian government fees API:

1. GET /fees
   - Query fees table with optional filters: category, state, search
   - Include relationships: subcategory, category, agency, source
   - Add pagination: limit (default 50), offset (default 0)
   - Return JSON with data array and metadata

2. GET /fees/{id}
   - Get single fee by ID with all relationships
   - Return 404 if not found
   - Include subcategory, category, source, and agency data

3. GET /categories
   - List all categories
   - Include count of fees in each category
   - Return with display_name and description

4. GET /fees/search
   - Accept 'q' query parameter (required, minimum 2 characters)
   - Search in fee name and description using case-insensitive match
   - Limit to 20 results
   - Include all relationships

5. GET /metadata
   - Return API statistics (total fees, categories, agencies)
   - Include last database update timestamp
   - Return API version number
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;AI delivered in ~30 minutes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complete XanoScript code for all 5 endpoints&lt;/li&gt;
&lt;li&gt;Database query structures with joins&lt;/li&gt;
&lt;li&gt;Basic input validation&lt;/li&gt;
&lt;li&gt;Pagination logic&lt;/li&gt;
&lt;li&gt;Error handling with preconditions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Time saved:&lt;/strong&gt; ~6 hours of boilerplate coding&lt;/p&gt;




&lt;h2&gt;
  
  
  How I Refined the AI-Generated Code
&lt;/h2&gt;

&lt;p&gt;AI gave me a great starting point, but I had to fix critical bugs and add production features. Here are the key refinements:&lt;/p&gt;

&lt;h3&gt;
  
  
  Issue #1: Invalid &lt;code&gt;eval&lt;/code&gt; Syntax - CRITICAL BUG
&lt;/h3&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%2Fd8nc03svgozh291whp3t.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%2Fd8nc03svgozh291whp3t.png" alt=" " width="800" height="442"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;AI Generated (GET /fees/{id}):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;category&lt;/span&gt;   &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;$db&lt;/span&gt;&lt;span class="p"&gt;.{}&lt;/span&gt;
  &lt;span class="nl"&gt;subcategory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;$db&lt;/span&gt;&lt;span class="p"&gt;.{}&lt;/span&gt;
  &lt;span class="nl"&gt;agency&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;$db&lt;/span&gt;&lt;span class="p"&gt;.{}&lt;/span&gt;
  &lt;span class="nl"&gt;source&lt;/span&gt;     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;$db&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;&lt;strong&gt;The Problem:&lt;/strong&gt; &lt;code&gt;$db.{}&lt;/code&gt; is invalid XanoScript syntax. This caused relationships to fail silently—no error in development, but incomplete data in production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My Fix:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Removed invalid eval block&lt;/span&gt;
&lt;span class="c1"&gt;// Used db.get to fetch relationships separately&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;$subcategory&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;subcategories&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;$fee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subcategory_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;$category&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;categories&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;$subcategory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;$source&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sources&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;$fee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;$agency&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;agencies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;$source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;agency_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Then nested them properly using var.update&lt;/span&gt;
&lt;span class="nx"&gt;$fee&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="nl"&gt;subcategory&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="nx"&gt;$subcategory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;$category&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;source&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="nx"&gt;$source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="nx"&gt;agency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;$agency&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;&lt;strong&gt;Impact:&lt;/strong&gt; Relationships now properly included in every response. API went from returning incomplete data to being production-ready.&lt;/p&gt;




&lt;h3&gt;
  
  
  Issue #2: N+1 Query Performance Problem
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;AI Generated (GET /categories):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;foreach &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$categories&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;$category&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Query fees for EACH category individually - terrible for performance!&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;$fee_count&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fees&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
      &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;subcategory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;category_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;$category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;count&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;&lt;strong&gt;The Problem:&lt;/strong&gt; If you have 6 categories, this makes 6 separate database queries. Would fail under load.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My Optimization:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Single query with proper aggregation&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;$fee_counts&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fees&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
      &lt;span class="na"&gt;subcategories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;category_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;categories.id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;group_by&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;categories.id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;category_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;categories.id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;fee_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;COUNT(fees.id)&lt;/span&gt;&lt;span class="dl"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Impact:&lt;/strong&gt; Reduced database queries from 6 to 1. Response time improved by ~60%.&lt;/p&gt;




&lt;h3&gt;
  
  
  Issue #3: Empty Results Bug
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Problem:&lt;/strong&gt; When calling &lt;code&gt;/fees&lt;/code&gt; with no filters, API returned &lt;code&gt;{"items":[],"itemsTotal":0}&lt;/code&gt; despite having 87 fees in the database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Root Cause:&lt;/strong&gt; The &lt;code&gt;where&lt;/code&gt; clause was too restrictive. When optional filters were &lt;code&gt;null&lt;/code&gt;, the logical AND conditions were filtering out all records.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My Fix:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Added explicit null/empty checks for each optional filter&lt;/span&gt;
&lt;span class="nx"&gt;where&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$search_filter&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;$search_filter&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; 
   &lt;span class="nx"&gt;$db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fees&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;$search_filter&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; 
   &lt;span class="nx"&gt;$db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fees&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;$search_filter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; 
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$category_filter&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;$category_filter&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; 
   &lt;span class="nx"&gt;$db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;$category_filter&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; 
   &lt;span class="nx"&gt;$db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;$category_filter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; 
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$state_filter&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;$state_filter&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; 
   &lt;span class="nx"&gt;$db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fees&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;$state_filter&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;&lt;strong&gt;Impact:&lt;/strong&gt; API now correctly returns all fees when no filters are applied, and properly filters when they are.&lt;/p&gt;




&lt;h3&gt;
  
  
  Issue #4: Incorrect Sort Syntax
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;AI Generated:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;sort&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$db.fees.updated_at&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;desc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The Problem:&lt;/strong&gt; XanoScript doesn't use &lt;code&gt;$db.&lt;/code&gt; prefix in sort blocks. Caused silent sorting failures.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My Fix:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;sort&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fees&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;updated_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;desc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Impact:&lt;/strong&gt; Last updated fees now correctly sorted by timestamp.&lt;/p&gt;




&lt;h3&gt;
  
  
  What I Added Beyond AI
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. API Key Authentication System&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;auth_api_key&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Extract and validate API key&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;$api_key&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$http_query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;api_key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;$api_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ERROR_CODE_ACCESS_DENIED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Missing API Key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Query and validate&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;$key_record&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;api_keys&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
      &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;$api_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="na"&gt;is_active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; 
    &lt;span class="p"&gt;})&lt;/span&gt; 
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;$key_record&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ERROR_CODE_ACCESS_DENIED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid or inactive API Key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Update usage stats&lt;/span&gt;
  &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;api_keys&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;$key_record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;request_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;$key_record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request_count&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="na"&gt;last_request_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;now&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="nx"&gt;$key_record&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Standardized Error Responses&lt;/strong&gt;&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;"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;"ERROR_CODE_ACCESS_DENIED"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Invalid or inactive API Key."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;401&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;&lt;strong&gt;3. Comprehensive Documentation&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full API reference with request/response examples&lt;/li&gt;
&lt;li&gt;Quick Start guide (5 minutes to first API call)&lt;/li&gt;
&lt;li&gt;Code examples in JavaScript, Python, and cURL&lt;/li&gt;
&lt;li&gt;Data sources reference with official URLs&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  The Numbers: AI vs Human Contribution
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;AI&lt;/th&gt;
&lt;th&gt;Human&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;30 minutes&lt;/td&gt;
&lt;td&gt;4-5 hours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Code Generated&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~500 lines&lt;/td&gt;
&lt;td&gt;~300 lines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Critical Bugs Found&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Production Features&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Basic CRUD&lt;/td&gt;
&lt;td&gt;Auth, optimization, error handling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Documentation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Complete&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Total Development Time:&lt;/strong&gt; ~5 hours (would have been 10-12 hours without AI)&lt;/p&gt;




&lt;h2&gt;
  
  
  My Experience with Xano
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What I Found Most Helpful
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Visual Database Designer&lt;/strong&gt;&lt;br&gt;
Building the relational database schema with proper foreign keys was intuitive. The visual interface made it easy to see relationships between tables (fees → subcategories → categories → agencies).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Built-in API Testing&lt;/strong&gt;&lt;br&gt;
The "Run &amp;amp; Debug" feature in the API builder was invaluable. I could test endpoints immediately without deploying or using external tools. This caught bugs early.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. XanoScript Flexibility&lt;/strong&gt;&lt;br&gt;
Having both visual blocks and code gave me the best of both worlds. For simple queries, I used the visual builder. For complex logic (like the authentication function), I wrote XanoScript directly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. One-Click Deployment&lt;/strong&gt;&lt;br&gt;
No server setup, no deployment configuration, no DevOps complexity. Just build and it's live. This saved hours of infrastructure work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. PostgreSQL Under the Hood&lt;/strong&gt;&lt;br&gt;
Knowing I had a real relational database with proper ACID guarantees gave me confidence. This isn't a toy database—it's production-grade.&lt;/p&gt;


&lt;h3&gt;
  
  
  Challenges I Faced
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. XanoScript Learning Curve&lt;/strong&gt;&lt;br&gt;
Coming from Java/JavaScript/Python, XanoScript syntax had quirks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$variable&lt;/code&gt; vs &lt;code&gt;variable&lt;/code&gt; naming conventions&lt;/li&gt;
&lt;li&gt;When to use &lt;code&gt;eval&lt;/code&gt; blocks (spoiler: less than I thought)&lt;/li&gt;
&lt;li&gt;Sort/filter syntax differences from standard SQL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Trial and error, plus reading Xano docs. The AI-generated code gave me examples to learn from, even when it had bugs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Debugging AI-Generated Code&lt;/strong&gt;&lt;br&gt;
AI confidently generated invalid syntax (&lt;code&gt;$db.{}&lt;/code&gt;) that looked plausible. Without testing, I would have shipped broken code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson Learned:&lt;/strong&gt; Always test AI-generated code immediately. AI is great at structure but can miss framework-specific nuances.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Documentation Gaps&lt;/strong&gt;&lt;br&gt;
Some XanoScript features weren't well-documented online. I had to experiment to figure out the correct syntax for complex joins and aggregations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Used the Xano community forums and tested different approaches until I found what worked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. N+1 Query Gotcha&lt;/strong&gt;&lt;br&gt;
It was easy to accidentally create performance problems with nested loops. The visual builder doesn't warn you about N+1 queries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Always think about database query patterns. Single complex query &amp;gt; multiple simple queries.&lt;/p&gt;


&lt;h3&gt;
  
  
  What Made This Project Successful
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Winning Combination:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Xano&lt;/strong&gt; handled infrastructure and deployment&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;AI&lt;/strong&gt; generated boilerplate and structure quickly&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Human expertise&lt;/strong&gt; fixed bugs, optimized performance, added production features&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Real data&lt;/strong&gt; from official government sources made it valuable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;None of these alone would have worked.&lt;/strong&gt; But together? I built a production-ready API in ~5 hours that would have taken 2-3 days manually.&lt;/p&gt;


&lt;h3&gt;
  
  
  Would I Use Xano Again?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Absolutely.&lt;/strong&gt; For rapid API development, especially for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hackathons&lt;/strong&gt; - Speed to deployment is unbeatable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MVPs&lt;/strong&gt; - Get to market fast, validate ideas&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internal tools&lt;/strong&gt; - Build CRUD APIs in hours, not days&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prototypes&lt;/strong&gt; - Prove concepts before investing in custom infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When I might not use it:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extremely high-scale applications requiring custom infrastructure&lt;/li&gt;
&lt;li&gt;Projects needing specific database features outside PostgreSQL&lt;/li&gt;
&lt;li&gt;Complex real-time features requiring WebSockets at scale&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But for 90% of backend API projects? &lt;strong&gt;Xano + AI is a game-changer.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Impact &amp;amp; Future Plans
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Who Can Use This API?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;🏦 Fintech Companies:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Budget calculators including government fees&lt;/li&gt;
&lt;li&gt;Payment platforms for government services&lt;/li&gt;
&lt;li&gt;Financial planning apps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;📱 Mobile Apps:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Citizen services super-apps&lt;/li&gt;
&lt;li&gt;Student planning tools&lt;/li&gt;
&lt;li&gt;Government service aggregators&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;🤖 Chatbots:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WhatsApp bots for fee inquiries&lt;/li&gt;
&lt;li&gt;USSD services for feature phones&lt;/li&gt;
&lt;li&gt;AI government assistants&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  What's Next
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Immediate (v1.1):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implement rate limiting (100 req/hour)&lt;/li&gt;
&lt;li&gt;Add webhook support for fee updates&lt;/li&gt;
&lt;li&gt;Create admin dashboard for data management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Future (v2.0):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expand to all 36 Nigerian states&lt;/li&gt;
&lt;li&gt;Historical fee tracking (price changes)&lt;/li&gt;
&lt;li&gt;Multi-language support&lt;/li&gt;
&lt;li&gt;Mobile SDK&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Long-term Vision:&lt;/strong&gt;&lt;br&gt;
Transform into a comprehensive government services platform with payment processing, application tracking, and document verification.&lt;/p&gt;


&lt;h2&gt;
  
  
  Data Sources
&lt;/h2&gt;

&lt;p&gt;All fees sourced from official government documents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;NIMC:&lt;/strong&gt; SERVICE_LEVEL_AGREEMENT_2025_.pdf&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NIS:&lt;/strong&gt; Official Immigration Service SLA&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NECO:&lt;/strong&gt; Official exam fees from neco.gov.ng&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JAMB:&lt;/strong&gt; Payment services from jamb.gov.ng&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NERC/EKEDC:&lt;/strong&gt; Official tariff plans from ekedp.com&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every fee includes &lt;code&gt;verification_url&lt;/code&gt; linking to the official source for transparency.&lt;/p&gt;


&lt;h2&gt;
  
  
  Try It Now!
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Test API Key:&lt;/strong&gt; &lt;code&gt;nga_b6cf98a60bda43ba8cf54af9dbd87260&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick Test:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s1"&gt;'https://xmlb-8xh6-ww1h.n7e.xano.io/api:public/fees/search?q=passport&amp;amp;api_key=nga_b6cf98a60bda43ba8cf54af9dbd87260'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Full Documentation:&lt;/strong&gt; &lt;a href="https://github.com/AbdulmalikAlayande/xano-ai-hackathon/" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt; (includes Quick Start guide, complete API reference, and code examples)&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This project proves that &lt;strong&gt;AI-assisted development works best as a partnership&lt;/strong&gt;: AI provides speed and structure, humans provide critical thinking and domain expertise.&lt;/p&gt;

&lt;p&gt;The Nigerian Government Fees API solves a real problem affecting millions. By centralizing scattered information into one well-documented API, we're removing barriers to accessing essential government services.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;More importantly, this is just the beginning.&lt;/strong&gt; With a solid foundation, this can grow into a platform that truly improves how Nigerian citizens interact with public services.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Questions? Want to contribute? Drop a comment below! 🚀&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>xanochallenge</category>
      <category>api</category>
      <category>backend</category>
    </item>
  </channel>
</rss>
