diff --git a/app/app/settings.py b/app/app/settings.py
index 9e33ac6..11495a8 100644
--- a/app/app/settings.py
+++ b/app/app/settings.py
@@ -42,6 +42,7 @@
     'rest_framework.authtoken',
     'drf_spectacular',
     'user',
+    'recipe',
 ]
 
 MIDDLEWARE = [
diff --git a/app/app/urls.py b/app/app/urls.py
index 0890765..9d3a468 100644
--- a/app/app/urls.py
+++ b/app/app/urls.py
@@ -22,5 +22,8 @@
     path('admin/', admin.site.urls),
     path('api/schema/', SpectacularAPIView.as_view(), name='api-schema'),
     path('api/docs/', SpectacularSwaggerView.as_view(url_name='api-schema'), name='api-docs'),
-    path('api/user/', include('user.urls'))
+    path('api/user/', include('user.urls')),
+    path('api/recipe/', include('recipe.urls')),
 ]
+
+# Here this includes all the urls which we have defined in the recipe urls and other files 
\ No newline at end of file
diff --git a/app/core/admin.py b/app/core/admin.py
index ddd09cc..e8d06e0 100644
--- a/app/core/admin.py
+++ b/app/core/admin.py
@@ -23,4 +23,5 @@ class UserAdmin(BaseUserAdmin):
     )
     
 
-admin.site.register(models.User, UserAdmin)
\ No newline at end of file
+admin.site.register(models.User, UserAdmin)
+admin.site.register(models.Recipe)
\ No newline at end of file
diff --git a/app/core/migrations/0002_recipe.py b/app/core/migrations/0002_recipe.py
new file mode 100644
index 0000000..29a2c55
--- /dev/null
+++ b/app/core/migrations/0002_recipe.py
@@ -0,0 +1,27 @@
+# Generated by Django 3.2.25 on 2024-08-24 15:09
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Recipe',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('title', models.CharField(max_length=255)),
+                ('description', models.TextField(blank=True)),
+                ('time_minutes', models.IntegerField()),
+                ('price', models.DecimalField(decimal_places=2, max_digits=5)),
+                ('link', models.CharField(blank=True, max_length=255)),
+                ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+            ],
+        ),
+    ]
diff --git a/app/core/models.py b/app/core/models.py
index 7fae641..4bc76a4 100644
--- a/app/core/models.py
+++ b/app/core/models.py
@@ -4,7 +4,7 @@
 """
 Database model
 """
-
+from django.conf import settings
 from django.db import models 
 from django.contrib.auth.models import (
     AbstractBaseUser, 
@@ -40,4 +40,17 @@ class User(AbstractBaseUser, PermissionsMixin):
     # assigning the UserManager to objects
     objects = UserManager()
 
-    USERNAME_FIELD = 'email'
\ No newline at end of file
+    USERNAME_FIELD = 'email'
+
+class Recipe(models.Model):
+    """Recipe model"""
+    # Here we use settings.AUTH_USER_MODEL to reference the user model in case we change the user model in the future this is a best practice
+    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
+    title = models.CharField(max_length=255)
+    description = models.TextField(blank=True)
+    time_minutes = models.IntegerField()
+    price = models.DecimalField(max_digits=5, decimal_places=2)
+    link = models.CharField(max_length=255, blank=True)
+
+    def __str__(self):
+        return self.title   
\ No newline at end of file
diff --git a/app/core/tests/test_models.py b/app/core/tests/test_models.py
index 392f072..2237b7e 100644
--- a/app/core/tests/test_models.py
+++ b/app/core/tests/test_models.py
@@ -1,10 +1,13 @@
 """
 Test for models
 """
+from decimal import Decimal
 
 from django.test import TestCase
 from django.contrib.auth import get_user_model
 
+from core import models
+
 class ModelTests(TestCase):
     """Test for models"""
     
@@ -42,4 +45,20 @@ def test_create_new_superuser(self):
         """Test creating a new superuser"""
         user = get_user_model().objects.create_superuser('test@example.com', 'test123')
         self.assertTrue(user.is_superuser)
-        self.assertTrue(user.is_staff)
\ No newline at end of file
+        self.assertTrue(user.is_staff)
+
+    def test_create_recipe(self):
+        """Test creating a new recipe"""
+        user = get_user_model().objects.create_user(
+            'test@example.com', 
+            'test123')
+        recipe = models.Recipe.objects.create(
+            user=user,
+            title='Sample Recipe',
+            time_minutes=5,
+            price=Decimal(
+                '5.00'),
+            description='Sample Description'
+            )
+        self.assertEqual(str(recipe), recipe.title)
+        
\ No newline at end of file
diff --git a/app/recipe/__init__.py b/app/recipe/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/app/recipe/apps.py b/app/recipe/apps.py
new file mode 100644
index 0000000..9133199
--- /dev/null
+++ b/app/recipe/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class RecipeConfig(AppConfig):
+    default_auto_field = 'django.db.models.BigAutoField'
+    name = 'recipe'
diff --git a/app/recipe/serializers.py b/app/recipe/serializers.py
new file mode 100644
index 0000000..6059e2b
--- /dev/null
+++ b/app/recipe/serializers.py
@@ -0,0 +1,22 @@
+"""
+Serialiers for recipe APIs 
+"""
+
+from rest_framework import serializers
+from core.models import Recipe
+
+class RecipeSerializer(serializers.ModelSerializer):
+    """Serializer for recipe objects"""
+
+    # Here it tells django we want to use the model Recipe and the fields we want to use
+    class Meta:
+        model = Recipe
+        fields = ('id', 'title', 'time_minutes', 'price', 'link')
+        read_only_fields = ('id',)
+
+class RecipeDetailSerializer(RecipeSerializer):
+    """Serializer for recipe detail objects"""
+    # Here we are extending the RecipeSerializer and adding the extra fields
+    class Meta(RecipeSerializer.Meta):
+        fields = RecipeSerializer.Meta.fields + ('ingredients', 'tags')
+        read_only_fields = ('id',)
diff --git a/app/recipe/tests/__init__.py b/app/recipe/tests/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/app/recipe/tests/test_recipe_api.py b/app/recipe/tests/test_recipe_api.py
new file mode 100644
index 0000000..2392221
--- /dev/null
+++ b/app/recipe/tests/test_recipe_api.py
@@ -0,0 +1,95 @@
+"""
+Tests for recipe APIs.
+"""
+
+from decimal import Decimal
+
+from django.contrib.auth import get_user_model
+from django.test import TestCase
+from django.urls import reverse
+
+from rest_framework import status
+from rest_framework.test import APIClient
+
+from core.models import Recipe
+
+from recipe.serializers import RecipeSerializer, RecipeDetailSerializer
+
+RECIPE_URL = reverse('recipe:recipe-list')
+
+def detail_url(recipe_id):
+    """Return recipe detail URL"""
+    return reverse('recipe:recipe-detail', args=[recipe_id]) 
+
+def create_recipe(user, **params):
+    """Create and return a sample recipe"""
+    defaults = {
+        'title': 'Sample Recipe',
+        'time_minutes': 10,
+        'price': Decimal('5.00'),
+        'description': 'Sample description',
+        'link': 'https://sample.com/recipe'
+    }
+    defaults.update(params)
+
+    return Recipe.objects.create(user=user, **defaults)
+
+
+class PublicRecipeAPITests(TestCase):
+    """Test unauthenticated recipe API access"""
+
+    def setUp(self):
+        self.client = APIClient()
+
+    def test_auth_required(self):
+        """Test that authentication is required"""
+        res = self.client.get(reverse('recipe:recipe-list'))
+        self.assertEqual(res.status_code, status.HTTP_401_UNAUTHORIZED)
+
+
+class PrivateRecipeApiTests(TestCase):
+    """Test authenticated recipe API access"""
+
+    def setUp(self):
+        self.client = APIClient()
+        self.user = get_user_model().objects.create_user(
+            'user@example.com',
+            'testpass')
+        self.client.force_authenticate(self.user)
+
+    def test_retrieve_recipes(self):
+        """Test retrieving a list of recipes"""
+        create_recipe(user=self.user)
+        create_recipe(user=self.user)
+
+        res = self.client.get(RECIPE_URL)
+
+        recipes = Recipe.objects.all().order_by('-id')
+        serializer = RecipeSerializer(recipes, many=True)
+        self.assertEqual(res.status_code, status.HTTP_200_OK)
+        self.assertEqual(res.data, serializer.data)
+
+    def test_recipes_limited_to_user(self):
+        """Test retrieving recipes for user"""
+        other_user = get_user_model().objects.create_user(
+            'other@example.com',
+            'password123')
+        create_recipe(user=other_user)
+        recipe = create_recipe(user=self.user)
+
+        res = self.client.get(RECIPE_URL)
+
+        recipes = Recipe.objects.filter(user=self.user)
+        serializer = RecipeSerializer(recipes, many=True)
+        self.assertEqual(res.status_code, status.HTTP_200_OK)   
+        self.assertEqual(res.data, serializer.data)
+
+    def test_get_recipe_detail(self):
+        """Test viewing a recipe detail"""
+        recipe = create_recipe(user=self.user)
+    
+        url = detail_url(recipe.id)
+        res = self.client.get(url)
+
+        serializer = RecipeDetailSerializer(recipe)
+        self.assertEqual(res.data, serializer.data)
\ No newline at end of file
diff --git a/app/recipe/urls.py b/app/recipe/urls.py
new file mode 100644
index 0000000..2d08ba2
--- /dev/null
+++ b/app/recipe/urls.py
@@ -0,0 +1,16 @@
+"""
+URL mapping for the recipe app is defined in app/recipe/urls.py. The URL mapping is then imported into the main project urls.py file.
+"""
+
+from django.urls import path, include 
+from rest_framework.routers import DefaultRouter
+from recipe import views
+
+router = DefaultRouter()
+router.register('recipes', views.RecipeViewSet)
+
+app_name = 'recipe'
+
+urlpatterns = [
+    path('', include(router.urls))
+] 
\ No newline at end of file
diff --git a/app/recipe/views.py b/app/recipe/views.py
new file mode 100644
index 0000000..8af951e
--- /dev/null
+++ b/app/recipe/views.py
@@ -0,0 +1,29 @@
+"""
+Views for the recipe APIs
+"""
+
+from rest_framework import viewsets
+from rest_framework.authentication import TokenAuthentication
+from rest_framework.permissions import IsAuthenticated
+
+
+from core.models import Recipe
+from recipe import serializers
+
+class RecipeViewSet(viewsets.ModelViewSet):
+    """Manage recipes in the database"""
+    serializer_class = serializers.RecipeDetailSerializer
+    queryset = Recipe.objects.all()
+    authentication_classes = [TokenAuthentication]
+    permission_classes = [IsAuthenticated]
+
+    def get_queryset(self):
+        """Retrieve the recipes for the authenticated user"""
+        return self.queryset.filter(user=self.request.user).order_by('-id')
+
+    def get_serializer_class(self):
+        """Return appropriate serializer class"""
+        if self.action == 'list':
+            return serializers.RecipeSerializer
+
+        return self.serializer_class
\ No newline at end of file