diff --git a/dj_iconify/types.py b/dj_iconify/types.py
index 0793421690bb1a0c997e5cc79c30bba070eb8a5d..5938203d85e0224d49239bf84dd5081c8f76ec38 100644
--- a/dj_iconify/types.py
+++ b/dj_iconify/types.py
@@ -6,6 +6,8 @@ from typing import Collection, Dict, List, Optional, Union
 from typing.io import TextIO
 import json
 
+from .util import split_css_unit
+
 
 class IconifyOptional:
     left: Optional[int] = None
@@ -46,13 +48,15 @@ class IconifyOptional:
 
 
 class IconifyIcon(IconifyOptional):
+    _collection: Optional["IconifyJSON"]
     body: str
 
     @classmethod
-    def from_dict(cls, src: dict) -> "IconifyIcon":
+    def from_dict(cls, src: dict, collection: Optional["IconifyJSON"] = None) -> "IconifyIcon":
         self = cls()
         self.body = src["body"]
         self._from_dict_optional(src)
+        self._collection = collection
         return self
 
     def as_dict(self) -> dict:
@@ -62,15 +66,92 @@ class IconifyIcon(IconifyOptional):
         res.update(self._as_dict_optional())
         return res
 
+    def get_width(self):
+        if self.width:
+            return self.width
+        elif self._collection and self._collection.width:
+            return self._collection.height
+        else:
+            return 16
+
+    def get_height(self):
+        if self.height:
+            return self.height
+        elif self._collection and self._collection.height:
+            return self._collection.height
+        else:
+            return 16
+
+    def as_svg(self, color: Optional[str] = None, width: Optional[str] = None, height: Optional[str] = None, rotate: Optional[str] = None, flip: Optional[str] = None, box: bool = False) -> str:
+        orig_width, orig_height = self.get_width(), self.get_height()
+
+        if width and (height is None or height.lower() == "auto"):
+            value, unit = split_css_unit(width)
+            height = str(value / (orig_width / orig_height)) + unit
+        elif height and (width is None or width.lower() == "auto"):
+            value, unit = split_css_unit(height)
+            width = str(value / (orig_height / orig_width)) + unit
+        elif width is None and height is None:
+            width, height = "1em", "1em"
+        svg_dim_attrs = f'width="{width}" height="{height}"'
+
+        head = f'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" {svg_dim_attrs} preserveAspectRatio="xMidYMid meet" viewBox="0 0 {orig_width} {orig_height}" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);">'
+        foot = "</svg>"
+
+        transform = []
+        if rotate is not None:
+            center_x, center_y = int(self.width / 2), int(self.height / 2)
+            if rotate.isnumeric():
+                deg = int(rotate) * 90
+            elif rotate.endswith("deg"):
+                deg = int(rotate[:-3])
+            transform.append(f"rotate({deg} {center_x} {center_y})")
+        if flip is not None:
+            flip = flip.split(",")
+            translate_x, translate_y = 0
+            scale_x, scale_y = 1, 1
+            if "horizontal" in flip:
+                translate_x = orig_width
+                scale_x = -1
+            if "vertical" in flip:
+                translate_y = orig_height
+                scale_y = -1
+            transform.append(f"translate({translate_x} {translate_z})")
+            transform.append(f"scale({scale_x} {scale_y})")
+        if transform:
+            transform = " ".join(transform)
+            g = f'<g transform="{transform}">', "</g>"
+        else:
+            g = "", ""
+
+        body = self.body
+        if color is not None:
+            body = body.replace('"currentColor"', f'"{color}"')
+
+        if box:
+            box = f'<rect x="0" y="0" width="{orig_width}" height="{orig_height}" fill="rgba(0, 0, 0, 0)" />'
+        else:
+            box = ""
+
+        svg = f"{head}{g[0]}{body}{g[1]}{box}{foot}"
+
+        return svg
+        
 
 class IconifyAlias(IconifyOptional):
+    _collection: Optional["IconifyJSON"]
     parent: str
 
+    def get_icon(self):
+        if self._collection:
+            return self._collection.get_icon(self.parent)
+
     @classmethod
-    def from_dict(cls, src: dict) -> "IconifyAlias":
+    def from_dict(cls, src: dict, collection: Optional["IconifyJSON"] = None) -> "IconifyAlias":
         self = cls()
         self.parent = src["parent"]
         self._from_dict_optional(src)
+        self._collection = collection
         return self
 
     def as_dict(self) -> dict:
@@ -87,6 +168,12 @@ class IconifyJSON(IconifyOptional):
     aliases: Optional[Dict[str, IconifyAlias]]
     not_found: List[str]
 
+    def get_icon(self, name: str):
+        if name in self.icons.keys():
+            return self.icons[name]
+        elif name in self.aliases.keys():
+            return self.aliases[name].get_icon()
+
     @classmethod
     def from_dict(cls, collection: Optional[dict] = None, only: Optional[Collection[str]] = None) -> "IconifyJSON":
         if collection is None:
@@ -104,13 +191,13 @@ class IconifyJSON(IconifyOptional):
         for name in only:
             icon_dict = collection["icons"].get(name, None)
             if icon_dict:
-                self.icons[name] = IconifyIcon.from_dict(icon_dict)
+                self.icons[name] = IconifyIcon.from_dict(icon_dict, collection=self)
                 continue
 
             alias_dict = collection["aliases"].get(name, None)
             if alias_dict:
-                self.aliases[name] = IconifyAlias.from_dict(alias_dict)
-                self.icons[alias_dict["parent"]] = IconifyIcon.from_dict(collection["icons"][alias_dict["parent"]])
+                self.aliases[name] = IconifyAlias.from_dict(alias_dict, collection=self)
+                self.icons[alias_dict["parent"]] = IconifyIcon.from_dict(collection["icons"][alias_dict["parent"]], collection=self)
                 continue
 
             self.not_found.append(name)
diff --git a/dj_iconify/urls.py b/dj_iconify/urls.py
index 3f097f2d0b6b050e40a591b47590b7cb7e573f1c..111b32ef1dea7591abeef04219a0a1ca0b231056 100644
--- a/dj_iconify/urls.py
+++ b/dj_iconify/urls.py
@@ -5,4 +5,5 @@ from . import views
 urlpatterns = [
     path('_config.js', views.ConfigView.as_view(), name='config.js'),
     re_path(r'^(?P<collection>[A-Za-z0-9-]+)\.(?P<format_>js(on)?)', views.IconifyJSONView.as_view(), name='iconify_json'),
+    re_path(r'^(?P<collection>[A-Za-z0-9-]+)/(?P<name>[A-Za-z0-9-]+)\.svg', views.IconifySVGView.as_view(), name='iconify_svg'),
 ]
diff --git a/dj_iconify/views.py b/dj_iconify/views.py
index 70f3e72d6cc88ef22d63206f8e5aee1988c88170..710c7bd37cb152fe7b88aadcd8dfee754eb92546 100644
--- a/dj_iconify/views.py
+++ b/dj_iconify/views.py
@@ -60,3 +60,36 @@ class IconifyJSONView(View):
             return HttpResponse(res, content_type="application/javascript")
         else:
             return HttpResponse(res, content_type="application/json")
+
+
+class IconifySVGView(View):
+    """Serve the Iconify SVG retrieval API."""
+    def get(self, request: HttpRequest, collection: str, name: str) -> HttpResponse:
+        """Retrieve a single icon as SVG."""
+        # General retrieval parameters
+        download = request.GET.get("download", "0").lower() in ("1", "true")
+        box = request.GET.get("box", "0").lower() in ("1", "true")
+
+        # SVG manipulation parameters
+        color = request.GET.get("color", None)
+        width = request.GET.get("width", None)
+        height = request.GET.get("height", None)
+        rotate = request.GET.get("rotate", None)
+        flip = request.GET.get("flip", None)
+
+        # Load icon set through Iconify types
+        collection_file = os.path.join(JSON_ROOT, "json", f"{collection}.json")
+        try:
+            icon_set = IconifyJSON.from_file(collection_file, only=[name])
+        except FileNotFoundError as exc:
+            raise Http404(f"Icon collection {collection} not found") from exc
+
+        # Generate SVG from icon
+        icon = icon_set.icons[name]
+        icon_svg = icon.as_svg(color=color, width=width, height=height, rotate=rotate, flip=flip, box=box)
+
+        # Form response
+        res = HttpResponse(icon_svg, content_type="image/svg+xml")
+        if download:
+            res["Content-Disposition"] = f"attachment; filename={name}.svg"
+        return res