diff --git a/.env.example b/.env.example
index d03b723c37bfd4aa65acfa2b3c7331443b24dfac..354969e0baee7da768e096a501bb1f406020178d 100644
--- a/.env.example
+++ b/.env.example
@@ -4,7 +4,7 @@ NODE_ENV=development
 DB_HOST=localhost
 DB_USER=postgres
 DB_PASSWORD=postgres
-DB_NAME=templatedb
+DB_NAME=apex_db
 DB_PORT=5432
 DB_URL=postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}
 
diff --git a/README.md b/README.md
index d311cb99f7697676e4c2aa68107908932267517b..9ade0d32628fb4bd06dbc241d6103788eb349150 100644
--- a/README.md
+++ b/README.md
@@ -10,12 +10,12 @@
 3. To install dependencies:
    ```sh
     bun install
+    cp .env.example .env
    ```
 
 4. Get the container up and running:
    ```sh
     docker compose up
-    cp .env.example .env
    ```
 
 5. set dev db
diff --git a/bunfig.toml b/bunfig.toml
index 4ae81d8a621167f7deaf6166f039ca188855ee0f..c9ba21b92e52b1f93ae68e957ed7aa0e689a1d5c 100644
--- a/bunfig.toml
+++ b/bunfig.toml
@@ -1,2 +1,4 @@
 preload = ["./src/preload.ts"]
-loglevel = "debug"
\ No newline at end of file
+
+[test]
+preload = ["./src/tests/preload-tests.ts"]
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
index 1183cb1d1002c0e241c0d345595323c0d9e0f2d9..98113da7176558f9aade7396bbefdcdb921bc9a7 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -3,13 +3,13 @@ services:
     image: postgres
     restart: always
     environment:
-      POSTGRES_DB: templatedb
+      POSTGRES_DB: apex_db
       POSTGRES_USER: postgres
       POSTGRES_PASSWORD: postgres
     ports:
       - "5432:5432"
     networks:
-      - tag_network
+      - apex_network
     volumes:
       - postgres_data:/var/lib/postgresql/data
 
@@ -17,4 +17,4 @@ volumes:
   postgres_data:
 
 networks:
-  tag_network:
+  apex_network:
diff --git a/package.json b/package.json
index b6947c8c135e0e3868233334e060991dfff08a94..0c2a4742b4681bc81468b2ff295ed1e1e82c0bcd 100644
--- a/package.json
+++ b/package.json
@@ -5,7 +5,8 @@
     "db:generate": "drizzle-kit generate",
     "db:migrate": "cross-env DB_MIGRATING=true bun run src/db/migrate.ts",
     "db:seed": "cross-env DB_SEEDING=true bun run src/db/seed.ts",
-    "db:studio": "drizzle-kit studio"
+    "db:studio": "drizzle-kit studio",
+    "route:test": "bun db:seed && bun test"
   },
   "dependencies": {
     "@hono/zod-validator": "^0.2.2",
diff --git a/src/db/migrations/0001_normal_marvex.sql b/src/db/migrations/0001_normal_marvex.sql
new file mode 100644
index 0000000000000000000000000000000000000000..155a5f42399dea7f8b8bc85d1a4e33d8cc0a6515
--- /dev/null
+++ b/src/db/migrations/0001_normal_marvex.sql
@@ -0,0 +1,14 @@
+CREATE TABLE IF NOT EXISTS "client" (
+	"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
+	"name" varchar(255) NOT NULL,
+	"cnpj" varchar(20) NOT NULL,
+	"industry" varchar(50),
+	"hq_address" varchar(255),
+	"phone" varchar(20),
+	"email" varchar(255),
+	"contact_person" varchar(255),
+	"created_at" timestamp DEFAULT now() NOT NULL,
+	"updated_at" timestamp DEFAULT now() NOT NULL,
+	CONSTRAINT "client_cnpj_unique" UNIQUE("cnpj"),
+	CONSTRAINT "client_email_unique" UNIQUE("email")
+);
diff --git a/src/db/migrations/0002_lying_beyonder.sql b/src/db/migrations/0002_lying_beyonder.sql
new file mode 100644
index 0000000000000000000000000000000000000000..4f04c1d4fdb04066c61edd026b9337dab1c9cd47
--- /dev/null
+++ b/src/db/migrations/0002_lying_beyonder.sql
@@ -0,0 +1,17 @@
+CREATE TABLE IF NOT EXISTS "credit_card" (
+	"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
+	"client_id" uuid NOT NULL,
+	"card_number" varchar(20) NOT NULL,
+	"cardholder_name" varchar(255) NOT NULL,
+	"expiration_date" date NOT NULL,
+	"cvv" varchar(5) NOT NULL,
+	"created_at" timestamp DEFAULT now() NOT NULL,
+	"updated_at" timestamp DEFAULT now() NOT NULL,
+	CONSTRAINT "credit_card_card_number_unique" UNIQUE("card_number")
+);
+--> statement-breakpoint
+DO $$ BEGIN
+ ALTER TABLE "credit_card" ADD CONSTRAINT "credit_card_client_id_client_id_fk" FOREIGN KEY ("client_id") REFERENCES "public"."client"("id") ON DELETE cascade ON UPDATE no action;
+EXCEPTION
+ WHEN duplicate_object THEN null;
+END $$;
diff --git a/src/db/migrations/meta/0001_snapshot.json b/src/db/migrations/meta/0001_snapshot.json
new file mode 100644
index 0000000000000000000000000000000000000000..e70b869a11b06f962410afc24b724738af8820e2
--- /dev/null
+++ b/src/db/migrations/meta/0001_snapshot.json
@@ -0,0 +1,146 @@
+{
+  "id": "b1587c07-98a9-4039-ae74-c1f6fc5f0823",
+  "prevId": "4cf89ad7-1672-440b-b964-dad35de18ec8",
+  "version": "7",
+  "dialect": "postgresql",
+  "tables": {
+    "public.client": {
+      "name": "client",
+      "schema": "",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "uuid",
+          "primaryKey": true,
+          "notNull": true,
+          "default": "gen_random_uuid()"
+        },
+        "name": {
+          "name": "name",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "cnpj": {
+          "name": "cnpj",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "industry": {
+          "name": "industry",
+          "type": "varchar(50)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "hq_address": {
+          "name": "hq_address",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "phone": {
+          "name": "phone",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "email": {
+          "name": "email",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "contact_person": {
+          "name": "contact_person",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "created_at": {
+          "name": "created_at",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "now()"
+        },
+        "updated_at": {
+          "name": "updated_at",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "now()"
+        }
+      },
+      "indexes": {},
+      "foreignKeys": {},
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {
+        "client_cnpj_unique": {
+          "name": "client_cnpj_unique",
+          "nullsNotDistinct": false,
+          "columns": [
+            "cnpj"
+          ]
+        },
+        "client_email_unique": {
+          "name": "client_email_unique",
+          "nullsNotDistinct": false,
+          "columns": [
+            "email"
+          ]
+        }
+      }
+    },
+    "public.user": {
+      "name": "user",
+      "schema": "",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "uuid",
+          "primaryKey": true,
+          "notNull": true,
+          "default": "gen_random_uuid()"
+        },
+        "username": {
+          "name": "username",
+          "type": "varchar",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "password": {
+          "name": "password",
+          "type": "varchar",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "name": {
+          "name": "name",
+          "type": "varchar",
+          "primaryKey": false,
+          "notNull": true
+        }
+      },
+      "indexes": {},
+      "foreignKeys": {},
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {
+        "user_username_unique": {
+          "name": "user_username_unique",
+          "nullsNotDistinct": false,
+          "columns": [
+            "username"
+          ]
+        }
+      }
+    }
+  },
+  "enums": {},
+  "schemas": {},
+  "_meta": {
+    "columns": {},
+    "schemas": {},
+    "tables": {}
+  }
+}
\ No newline at end of file
diff --git a/src/db/migrations/meta/0002_snapshot.json b/src/db/migrations/meta/0002_snapshot.json
new file mode 100644
index 0000000000000000000000000000000000000000..834cafdf4784afad23f49ab652d7e8a708d61f9c
--- /dev/null
+++ b/src/db/migrations/meta/0002_snapshot.json
@@ -0,0 +1,229 @@
+{
+  "id": "3e1ec9b7-7574-46ca-aec8-0f0fa2c41943",
+  "prevId": "b1587c07-98a9-4039-ae74-c1f6fc5f0823",
+  "version": "7",
+  "dialect": "postgresql",
+  "tables": {
+    "public.client": {
+      "name": "client",
+      "schema": "",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "uuid",
+          "primaryKey": true,
+          "notNull": true,
+          "default": "gen_random_uuid()"
+        },
+        "name": {
+          "name": "name",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "cnpj": {
+          "name": "cnpj",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "industry": {
+          "name": "industry",
+          "type": "varchar(50)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "hq_address": {
+          "name": "hq_address",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "phone": {
+          "name": "phone",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "email": {
+          "name": "email",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "contact_person": {
+          "name": "contact_person",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "created_at": {
+          "name": "created_at",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "now()"
+        },
+        "updated_at": {
+          "name": "updated_at",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "now()"
+        }
+      },
+      "indexes": {},
+      "foreignKeys": {},
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {
+        "client_cnpj_unique": {
+          "name": "client_cnpj_unique",
+          "nullsNotDistinct": false,
+          "columns": [
+            "cnpj"
+          ]
+        },
+        "client_email_unique": {
+          "name": "client_email_unique",
+          "nullsNotDistinct": false,
+          "columns": [
+            "email"
+          ]
+        }
+      }
+    },
+    "public.credit_card": {
+      "name": "credit_card",
+      "schema": "",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "uuid",
+          "primaryKey": true,
+          "notNull": true,
+          "default": "gen_random_uuid()"
+        },
+        "client_id": {
+          "name": "client_id",
+          "type": "uuid",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "card_number": {
+          "name": "card_number",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "cardholder_name": {
+          "name": "cardholder_name",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "expiration_date": {
+          "name": "expiration_date",
+          "type": "date",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "cvv": {
+          "name": "cvv",
+          "type": "varchar(5)",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "created_at": {
+          "name": "created_at",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "now()"
+        },
+        "updated_at": {
+          "name": "updated_at",
+          "type": "timestamp",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "now()"
+        }
+      },
+      "indexes": {},
+      "foreignKeys": {
+        "credit_card_client_id_client_id_fk": {
+          "name": "credit_card_client_id_client_id_fk",
+          "tableFrom": "credit_card",
+          "tableTo": "client",
+          "columnsFrom": [
+            "client_id"
+          ],
+          "columnsTo": [
+            "id"
+          ],
+          "onDelete": "cascade",
+          "onUpdate": "no action"
+        }
+      },
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {
+        "credit_card_card_number_unique": {
+          "name": "credit_card_card_number_unique",
+          "nullsNotDistinct": false,
+          "columns": [
+            "card_number"
+          ]
+        }
+      }
+    },
+    "public.user": {
+      "name": "user",
+      "schema": "",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "uuid",
+          "primaryKey": true,
+          "notNull": true,
+          "default": "gen_random_uuid()"
+        },
+        "username": {
+          "name": "username",
+          "type": "varchar",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "password": {
+          "name": "password",
+          "type": "varchar",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "name": {
+          "name": "name",
+          "type": "varchar",
+          "primaryKey": false,
+          "notNull": true
+        }
+      },
+      "indexes": {},
+      "foreignKeys": {},
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {
+        "user_username_unique": {
+          "name": "user_username_unique",
+          "nullsNotDistinct": false,
+          "columns": [
+            "username"
+          ]
+        }
+      }
+    }
+  },
+  "enums": {},
+  "schemas": {},
+  "_meta": {
+    "columns": {},
+    "schemas": {},
+    "tables": {}
+  }
+}
\ No newline at end of file
diff --git a/src/db/migrations/meta/_journal.json b/src/db/migrations/meta/_journal.json
index 600010d731beb84a0e2a0996864e2923a20e4a8e..f594e3b045559fd74218bea77832329246013875 100644
--- a/src/db/migrations/meta/_journal.json
+++ b/src/db/migrations/meta/_journal.json
@@ -8,6 +8,20 @@
       "when": 1719362169477,
       "tag": "0000_aspiring_frightful_four",
       "breakpoints": true
+    },
+    {
+      "idx": 1,
+      "version": "7",
+      "when": 1719970953846,
+      "tag": "0001_normal_marvex",
+      "breakpoints": true
+    },
+    {
+      "idx": 2,
+      "version": "7",
+      "when": 1720096335732,
+      "tag": "0002_lying_beyonder",
+      "breakpoints": true
     }
   ]
 }
\ No newline at end of file
diff --git a/src/db/repo/client.repo.ts b/src/db/repo/client.repo.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c2eecfbe026428e79bc4bf89ef4e138bce2d888e
--- /dev/null
+++ b/src/db/repo/client.repo.ts
@@ -0,0 +1,56 @@
+import { Service } from 'typedi'
+import type {
+  ClientInput,
+  ClientModel,
+  ClientUpdate,
+} from '../schema/client.model'
+import db from '..'
+import clientTable, { clientSchemas } from '../schema/client.model'
+import { eq } from 'drizzle-orm'
+
+@Service()
+export class ClientRepo {
+  async create(client: ClientInput): Promise<ClientModel> {
+    const [ret] = await db
+      .insert(clientTable)
+      .values(client)
+      .returning()
+
+    return clientSchemas.clientModelSchema.parse(ret)
+  }
+
+  async update(client: ClientUpdate): Promise<ClientModel> {
+    const [ret] = await db
+      .update(clientTable)
+      .set(client)
+      .where(eq(clientTable.id, client.id))
+      .returning()
+
+    return clientSchemas.clientModelSchema.parse(ret)
+  }
+
+  async delete(id: ClientModel['id']): Promise<ClientModel> {
+    const [ret] = await db
+      .delete(clientTable)
+      .where(eq(clientTable.id, id))
+      .returning()
+
+    return clientSchemas.clientModelSchema.parse(ret)
+  }
+
+  async find(
+    id: ClientModel['id']
+  ): Promise<ClientModel | undefined> {
+    const client = await db.query.clientTable.findFirst({
+      where: eq(clientTable.id, id),
+    })
+
+    return clientSchemas.clientModelSchema.parse(client)
+  }
+
+  async findMany(): Promise<ClientModel[]> {
+    return clientSchemas.clientModelSchema
+      .array()
+      .parse(await db.query.clientTable.findMany())
+  }
+}
diff --git a/src/db/repo/credit-card.repo.ts b/src/db/repo/credit-card.repo.ts
new file mode 100644
index 0000000000000000000000000000000000000000..460eec6709e19b38142add7ce9de412e6c1c289a
--- /dev/null
+++ b/src/db/repo/credit-card.repo.ts
@@ -0,0 +1,62 @@
+import { Service } from 'typedi'
+import type {
+  CreditCardInput,
+  CreditCardModel,
+  CreditCardUpdate,
+} from '../schema/credit-card.model'
+import creditCardTable, {
+  creditCardSchemas,
+} from '../schema/credit-card.model'
+import db from '..'
+import { eq } from 'drizzle-orm'
+
+@Service()
+export class CreditCardRepo {
+  async create(
+    creditCard: CreditCardInput
+  ): Promise<CreditCardModel> {
+    const [ret] = await db
+      .insert(creditCardTable)
+      .values(creditCard)
+      .returning()
+
+    return creditCardSchemas.creditCardModelSchema.parse(ret)
+  }
+
+  async update(
+    creditCard: CreditCardUpdate
+  ): Promise<CreditCardModel> {
+    const [ret] = await db
+      .update(creditCardTable)
+      .set(creditCard)
+      .where(eq(creditCardTable.id, creditCard.id))
+      .returning()
+
+    return creditCardSchemas.creditCardModelSchema.parse(ret)
+  }
+
+  async delete(id: CreditCardModel['id']): Promise<CreditCardModel> {
+    const [ret] = await db
+      .delete(creditCardTable)
+      .where(eq(creditCardTable.id, id))
+      .returning()
+
+    return creditCardSchemas.creditCardModelSchema.parse(ret)
+  }
+
+  async find(
+    id: CreditCardModel['id']
+  ): Promise<CreditCardModel | undefined> {
+    const creditCard = await db.query.creditCardTable.findFirst({
+      where: eq(creditCardTable.id, id),
+    })
+
+    return creditCardSchemas.creditCardModelSchema.parse(creditCard)
+  }
+
+  async findMany(): Promise<CreditCardModel[]> {
+    return creditCardSchemas.creditCardModelSchema
+      .array()
+      .parse(await db.query.creditCardTable.findMany())
+  }
+}
diff --git a/src/db/repo/user.repo.ts b/src/db/repo/user.repo.ts
index 8fd0c6d18c5c4863b9758cefa0013013cbc38eb6..c23d853fb3a28c3fcaff9507f9f37cdfa264cfe2 100644
--- a/src/db/repo/user.repo.ts
+++ b/src/db/repo/user.repo.ts
@@ -11,11 +11,9 @@ import { eq } from 'drizzle-orm'
 @Service()
 export class UserRepo {
   async findMany(): Promise<UserModel[]> {
-    return z.array(userSchemas.userModelSchema).parse(
-      await db.query.userTable.findMany({
-        limit: 100,
-      })
-    )
+    return z
+      .array(userSchemas.userModelSchema)
+      .parse(await db.query.userTable.findMany())
   }
 
   async findByUsername(
diff --git a/src/db/schema/client.model.ts b/src/db/schema/client.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a5a25f917af9e3b135085c7cc1986a8367fc814c
--- /dev/null
+++ b/src/db/schema/client.model.ts
@@ -0,0 +1,64 @@
+import { relations, sql } from 'drizzle-orm'
+import {
+  pgTable,
+  timestamp,
+  uuid,
+  varchar,
+} from 'drizzle-orm/pg-core'
+import { createInsertSchema, createSelectSchema } from 'drizzle-zod'
+import { z } from 'zod'
+import creditCardTable, {
+  creditCardSchemas,
+} from './credit-card.model'
+
+const clientTable = pgTable('client', {
+  id: uuid('id').primaryKey().defaultRandom(),
+  name: varchar('name', { length: 255 }).notNull(),
+  cnpj: varchar('cnpj', { length: 20 }).unique().notNull(),
+  industry: varchar('industry', { length: 50 }),
+  hqAddress: varchar('hq_address', { length: 255 }),
+  phone: varchar('phone', { length: 20 }),
+  email: varchar('email', { length: 255 }).unique(),
+  contactPerson: varchar('contact_person', { length: 255 }),
+  createdAt: timestamp('created_at', { mode: 'string' })
+    .notNull()
+    .defaultNow(),
+  updatedAt: timestamp('updated_at', { mode: 'string' })
+    .notNull()
+    .defaultNow()
+    .$onUpdate(() => sql`current_timestamp`),
+})
+
+export const clientTableRelations = relations(
+  clientTable,
+  ({ many }) => ({
+    creditCards: many(creditCardTable),
+  })
+)
+
+const clientModelSchema = createSelectSchema(clientTable).extend({
+  creditCards: creditCardSchemas.creditCardModelSchema
+    .array()
+    .optional(),
+})
+const clientDtoSchema = clientModelSchema
+const clientInputSchema = createInsertSchema(clientTable, {
+  email: (schema) => schema.email.email(),
+})
+const clientUpdateSchema = clientInputSchema
+  .partial()
+  .required({ id: true })
+
+export type ClientModel = z.infer<typeof clientModelSchema>
+export type ClientDto = z.infer<typeof clientDtoSchema>
+export type ClientInput = z.infer<typeof clientInputSchema>
+export type ClientUpdate = z.infer<typeof clientUpdateSchema>
+
+export const clientSchemas = {
+  clientModelSchema,
+  clientDtoSchema,
+  clientInputSchema,
+  clientUpdateSchema,
+}
+
+export default clientTable
diff --git a/src/db/schema/credit-card.model.ts b/src/db/schema/credit-card.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3182b8ae7e9e2f760226b1e41b5ccdc2d6727d5a
--- /dev/null
+++ b/src/db/schema/credit-card.model.ts
@@ -0,0 +1,73 @@
+import {
+  date,
+  pgTable,
+  timestamp,
+  uuid,
+  varchar,
+} from 'drizzle-orm/pg-core'
+import { createInsertSchema, createSelectSchema } from 'drizzle-zod'
+import type { z } from 'zod'
+import clientTable from './client.model'
+import { relations, sql } from 'drizzle-orm'
+
+const creditCardTable = pgTable('credit_card', {
+  id: uuid('id').primaryKey().defaultRandom(),
+  clientId: uuid('client_id')
+    .references(() => clientTable.id, { onDelete: 'cascade' })
+    .notNull(),
+  cardNumber: varchar('card_number', { length: 20 })
+    .unique()
+    .notNull(),
+  cardholderName: varchar('cardholder_name', {
+    length: 255,
+  }).notNull(),
+  expirationDate: date('expiration_date', {
+    mode: 'string',
+  }).notNull(),
+  cvv: varchar('cvv', { length: 5 }).notNull(),
+  createdAt: timestamp('created_at', {
+    mode: 'string',
+  })
+    .notNull()
+    .defaultNow(),
+  updatedAt: timestamp('updated_at', {
+    mode: 'string',
+  })
+    .notNull()
+    .defaultNow()
+    .$onUpdate(() => sql`current_timestamp`),
+})
+
+export const creditCardTableRelations = relations(
+  creditCardTable,
+  ({ one }) => ({
+    client: one(clientTable, {
+      fields: [creditCardTable.clientId],
+      references: [clientTable.id],
+    }),
+  })
+)
+
+const creditCardModelSchema = createSelectSchema(creditCardTable)
+const creditCardDtoSchema = creditCardModelSchema.omit({
+  cvv: true,
+  cardNumber: true,
+})
+const creditCardInputSchema = createInsertSchema(creditCardTable)
+const creditCardUpdateSchema = creditCardInputSchema
+  .partial()
+  .required({ id: true })
+
+export type CreditCardModel = z.infer<typeof creditCardModelSchema>
+export type CreditCardDto = z.infer<typeof creditCardDtoSchema>
+export type CreditCardInput = z.infer<typeof creditCardInputSchema>
+export type CreditCardUpdate = z.infer<typeof creditCardUpdateSchema>
+
+export const creditCardSchemas = {
+  creditCardModelSchema,
+  creditCardDtoSchema,
+  creditCardInputSchema,
+  creditCardUpdateSchema,
+}
+
+export default creditCardTable
diff --git a/src/db/schema/index.ts b/src/db/schema/index.ts
index 6a9894ef8f94573ccdda030a6a4c12cea2cf41ae..b357bcb9c0e9c9dbb96f519e0c2a36478a15f81b 100644
--- a/src/db/schema/index.ts
+++ b/src/db/schema/index.ts
@@ -1,5 +1,15 @@
 import userTable from './user.model'
+import clientTable, { clientTableRelations } from './client.model'
+import creditCardTable, {
+  creditCardTableRelations,
+} from './credit-card.model'
 
-export { userTable }
+export {
+  userTable,
+  clientTable,
+  clientTableRelations,
+  creditCardTable,
+  creditCardTableRelations,
+}
 
-export const tables = [userTable]
+export const tables = [userTable, clientTable, creditCardTable]
diff --git a/src/db/seed.ts b/src/db/seed.ts
index de1307e96f2b126ab6ccb0beee2ad2263a08603f..322a2bd8d415b7296946a83433a0821e4483ed75 100644
--- a/src/db/seed.ts
+++ b/src/db/seed.ts
@@ -5,7 +5,7 @@ import * as schema from '@/db/schema'
 import * as seeds from '@/db/seeds'
 
 if (!env.DB_SEEDING) {
-  throw new Error('You must sed DB_SEEDING to "true" when seeding')
+  throw new Error('You must set DB_SEEDING to "true" when seeding')
 }
 
 async function resetTable(db: db, table: Table) {
@@ -21,5 +21,7 @@ for (const table of schema.tables) {
 }
 
 await seeds.userSeed(db)
+await seeds.clientSeed(db)
+await seeds.creditCardSeed(db)
 
 await connection.end()
diff --git a/src/db/seeds/client.seed.ts b/src/db/seeds/client.seed.ts
new file mode 100644
index 0000000000000000000000000000000000000000..94b48dae9551a9cece4ff7cf221ce99ca220c8b7
--- /dev/null
+++ b/src/db/seeds/client.seed.ts
@@ -0,0 +1,110 @@
+import type db from '..'
+import type { ClientInput } from '../schema/client.model'
+import clientTable from '../schema/client.model'
+
+export default async function seed(db: db) {
+  await db.insert(clientTable).values(clientData)
+}
+
+const clientData: ClientInput[] = [
+  {
+    id: 'f1b9b3b4-0b3b-4b3b-8b3b-0b3b4b3b4b3b',
+    name: 'Acme Corp',
+    cnpj: '12.345.678/0001-91',
+    industry: 'Manufacturing',
+    hqAddress: '1234 Industry Rd, City',
+    phone: '123-456-7890',
+    email: 'contact@acmecorp.com',
+    contactPerson: 'John Doe',
+  },
+  {
+    id: '12345678-1234-1234-1234-123456789012',
+    name: 'Example Corp',
+    cnpj: '98.765.432/0001-21',
+    industry: 'Technology',
+    hqAddress: '5678 Tech St, City',
+    phone: '987-654-3210',
+    email: 'contact@examplecorp.com',
+    contactPerson: 'Jane Smith',
+  },
+  {
+    id: '87654321-4321-4321-4321-210987654321',
+    name: 'XYZ Corp',
+    cnpj: '11.223.344/0001-55',
+    industry: 'Finance',
+    hqAddress: '9876 Finance St, City',
+    phone: '555-555-5555',
+    email: 'contact@xyzcorp.com',
+    contactPerson: 'Bob Johnson',
+  },
+  {
+    id: '98765432-2345-2345-2345-543210987654',
+    name: 'ABC Corp',
+    cnpj: '99.888.777/0001-33',
+    industry: 'Retail',
+    hqAddress: '5432 Retail St, City',
+    phone: '111-222-3333',
+    email: 'contact@abccorp.com',
+    contactPerson: 'Alice Brown',
+  },
+  {
+    id: '23456789-3456-3456-3456-654321098765',
+    name: 'DEF Corp',
+    cnpj: '44.555.666/0001-44',
+    industry: 'Healthcare',
+    hqAddress: '8765 Healthcare St, City',
+    phone: '999-888-7777',
+    email: 'contact@defcorp.com',
+    contactPerson: 'David Wilson',
+  },
+  {
+    id: '34567890-4567-4567-4567-765432109876',
+    name: 'GHI Corp',
+    cnpj: '77.888.999/0001-66',
+    industry: 'Education',
+    hqAddress: '2345 Education St, City',
+    phone: '333-444-5555',
+    email: 'contact@ghicorp.com',
+    contactPerson: 'Grace Thompson',
+  },
+  {
+    id: '45678901-5678-5678-5678-876543210987',
+    name: 'JKL Corp',
+    cnpj: '22.333.444/0001-77',
+    industry: 'Hospitality',
+    hqAddress: '7654 Hospitality St, City',
+    phone: '777-666-5555',
+    email: 'contact@jklcorp.com',
+    contactPerson: 'James Davis',
+  },
+  {
+    id: '56789012-6789-6789-6789-987654321098',
+    name: 'MNO Corp',
+    cnpj: '66.777.888/0001-88',
+    industry: 'Transportation',
+    hqAddress: '1234 Transportation St, City',
+    phone: '222-111-9999',
+    email: 'contact@mnocorp.com',
+    contactPerson: 'Mary Johnson',
+  },
+  {
+    id: '67890123-7890-7890-7890-098765432109',
+    name: 'PQR Corp',
+    cnpj: '33.444.555/0001-99',
+    industry: 'Energy',
+    hqAddress: '9876 Energy St, City',
+    phone: '444-333-2222',
+    email: 'contact@pqrcorp.com',
+    contactPerson: 'Peter Wilson',
+  },
+  {
+    id: '78901234-8901-8901-8901-987654321098',
+    name: 'STU Corp',
+    cnpj: '55.666.777/0001-00',
+    industry: 'Telecommunications',
+    hqAddress: '5432 Telecom St, City',
+    phone: '888-999-0000',
+    email: 'contact@stucorp.com',
+    contactPerson: 'Sarah Brown',
+  },
+]
diff --git a/src/db/seeds/credit-card.seed.ts b/src/db/seeds/credit-card.seed.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6230f3f0278c983ac38c750caba319fa276a18b6
--- /dev/null
+++ b/src/db/seeds/credit-card.seed.ts
@@ -0,0 +1,52 @@
+import type db from '..'
+import { creditCardTable } from '../schema'
+import type { CreditCardInput } from '../schema/credit-card.model'
+
+export default async function seed(db: db) {
+  await db.insert(creditCardTable).values(creditCardData)
+}
+
+const creditCardData: CreditCardInput[] = [
+  {
+    clientId: 'f1b9b3b4-0b3b-4b3b-8b3b-0b3b4b3b4b3b',
+    cardNumber: '1234 5678 9012 3456',
+    cardholderName: 'John Doe',
+    expirationDate: '2025-12-31',
+    cvv: '123',
+  },
+  {
+    clientId: 'f1b9b3b4-0b3b-4b3b-8b3b-0b3b4b3b4b3b',
+    cardNumber: '9876 5432 1098 7654',
+    cardholderName: 'Jane Smith',
+    expirationDate: '2024-06-30',
+    cvv: '456',
+  },
+  {
+    clientId: '12345678-1234-1234-1234-123456789012',
+    cardNumber: '5555 4444 3333 2222',
+    cardholderName: 'Alice Johnson',
+    expirationDate: '2023-09-15',
+    cvv: '789',
+  },
+  {
+    clientId: '12345678-1234-1234-1234-123456789012',
+    cardNumber: '1111 2222 3333 4444',
+    cardholderName: 'Bob Williams',
+    expirationDate: '2026-03-01',
+    cvv: '012',
+  },
+  {
+    clientId: '12345678-1234-1234-1234-123456789012',
+    cardNumber: '9999 8888 7777 6666',
+    cardholderName: 'Sarah Davis',
+    expirationDate: '2025-11-30',
+    cvv: '345',
+  },
+  {
+    clientId: '87654321-4321-4321-4321-210987654321',
+    cardNumber: '4444 5555 6666 7777',
+    cardholderName: 'Michael Brown',
+    expirationDate: '2022-07-10',
+    cvv: '678',
+  },
+]
diff --git a/src/db/seeds/index.ts b/src/db/seeds/index.ts
index 4f9fb7bc3e6114822c37691514e30d4610f13237..47dd12191d399d235cb53688dd0d23c51045b239 100644
--- a/src/db/seeds/index.ts
+++ b/src/db/seeds/index.ts
@@ -1 +1,3 @@
 export { default as userSeed } from './user.seed'
+export { default as clientSeed } from './client.seed'
+export { default as creditCardSeed } from './credit-card.seed'
diff --git a/src/index.ts b/src/index.ts
index 0225f616dffaf88af0b060da935c1d2bbf881177..fd1950d5f581c1e341d3cc7d9908f0e4aab82b0e 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -10,12 +10,15 @@ import { uploaderRouter } from './routes/uploader.route'
 import { prettyJSON } from 'hono/pretty-json'
 import { cors } from 'hono/cors'
 import { bodyLimit } from 'hono/body-limit'
+import { clientRouter } from './routes/client.route'
+import { HttpStatus, createApexError } from './services/error.service'
+import { creditCardRouter } from './routes/credit-card.route'
 
 const app = new Hono()
 
 app.use('*', logger())
 app.use('*', prettyJSON())
-app.use('/api/*', cors())
+app.use('*', cors())
 app.use(
   '/api/*',
   jwt({
@@ -27,7 +30,16 @@ app.use(
   bodyLimit({
     maxSize: 50 * 1024 * 1024, // 50mb
     onError(c) {
-      return c.json('overflow', 413)
+      return c.json(
+        createApexError({
+          status: 'error',
+          message: 'File is too big. Current limit is 50mb',
+          code: HttpStatus.PAYLOAD_TOO_LARGE,
+          path: c.req.routePath,
+          suggestion: 'Reduce the size of your file and try again',
+        }),
+        413
+      )
     },
   })
 )
@@ -36,9 +48,12 @@ app.get('/', (c) => c.json({ message: 'sv running on /api' }))
 
 app.route('auth', authRouter)
 
-const api = app.basePath('/api')
-api.route('/user', userRouter)
-api.route('/upload', uploaderRouter)
+app
+  .basePath('/api')
+  .route('/user', userRouter)
+  .route('/client', clientRouter)
+  .route('/credit-card', creditCardRouter)
+  .route('/upload', uploaderRouter)
 
 export default app
 export type AppType = typeof app
diff --git a/src/routes/auth.route.ts b/src/routes/auth.route.ts
index a3cf6db945668cb2c9bcfd169c4f3b58936776d4..f3d0c2f8c45198dba32680542651ef62f9d53a79 100644
--- a/src/routes/auth.route.ts
+++ b/src/routes/auth.route.ts
@@ -1,5 +1,6 @@
 import { authSchema } from '@/db/repo/auth.repo'
 import { AuhtService } from '@/services/auth.service'
+import { HttpStatus, createApexError } from '@/services/error.service'
 import { zValidator } from '@hono/zod-validator'
 import { Hono } from 'hono'
 import Container from 'typedi'
@@ -17,8 +18,16 @@ export const authRouter = new Hono().post(
 
       return c.json({ token })
     } catch (e) {
-      console.log(e)
-      return c.notFound()
+      return c.json(
+        createApexError({
+          status: 'error',
+          code: HttpStatus.NOT_FOUND,
+          message: 'Invalid or inexistent user',
+          path: c.req.routePath,
+          suggestion: 'Check your credentials',
+        }),
+        HttpStatus.NOT_FOUND
+      )
     }
   }
 )
diff --git a/src/routes/client.route.ts b/src/routes/client.route.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7682c33687e0e9d2e0dbc69240119b61dd382112
--- /dev/null
+++ b/src/routes/client.route.ts
@@ -0,0 +1,108 @@
+import { ClientService } from '@/services/client.service'
+import Container from 'typedi'
+import { honoWithJwt } from '..'
+import { zValidator } from '@hono/zod-validator'
+import { clientSchemas } from '@/db/schema/client.model'
+import { HttpStatus, createApexError } from '@/services/error.service'
+
+const service = Container.get(ClientService)
+
+export const clientRouter = honoWithJwt()
+  .post(
+    '/create',
+    zValidator('json', clientSchemas.clientInputSchema),
+    async (c) => {
+      try {
+        const input = await c.req.valid('json')
+
+        const client = clientSchemas.clientDtoSchema.parse(
+          await service.create(input)
+        )
+
+        return c.json({ client })
+      } catch (e) {
+        return c.json(
+          createApexError({
+            status: 'error',
+            message: 'could not create client',
+            code: HttpStatus.BAD_REQUEST,
+            path: c.req.routePath,
+            suggestion: 'check the input and try again',
+          }),
+          HttpStatus.BAD_REQUEST
+        )
+      }
+    }
+  )
+  .post(
+    '/update',
+    zValidator('json', clientSchemas.clientUpdateSchema),
+    async (c) => {
+      try {
+        const input = await c.req.valid('json')
+
+        const client = clientSchemas.clientDtoSchema.parse(
+          await service.update(input)
+        )
+
+        return c.json({ client })
+      } catch (e) {
+        console.log(e)
+
+        return c.json(
+          createApexError({
+            status: 'error',
+            message: 'could not update client',
+            code: HttpStatus.BAD_REQUEST,
+            path: c.req.routePath,
+            suggestion: 'check the input and try again',
+          }),
+          HttpStatus.BAD_REQUEST
+        )
+      }
+    }
+  )
+  .post('/delete/:id', async (c) => {
+    try {
+      const id = c.req.param('id')
+
+      const client = clientSchemas.clientDtoSchema.parse(
+        await service.delete(id)
+      )
+
+      return c.json({ client })
+    } catch (e) {
+      return c.json(
+        createApexError({
+          status: 'error',
+          message: 'could not delete client',
+          code: HttpStatus.BAD_REQUEST,
+          path: c.req.routePath,
+          suggestion: 'check the input and try again',
+        }),
+        HttpStatus.BAD_REQUEST
+      )
+    }
+  })
+  .get('/:id', async (c) => {
+    try {
+      const id = c.req.param('id')
+
+      const client = clientSchemas.clientDtoSchema.parse(
+        await service.find(id)
+      )
+
+      return c.json({ client })
+    } catch (e) {
+      return c.json(
+        createApexError({
+          status: 'error',
+          message: 'could not find client',
+          code: HttpStatus.NOT_FOUND,
+          path: c.req.routePath,
+          suggestion: 'are you sure this client exists?',
+        }),
+        HttpStatus.NOT_FOUND
+      )
+    }
+  })
diff --git a/src/routes/credit-card.route.ts b/src/routes/credit-card.route.ts
new file mode 100644
index 0000000000000000000000000000000000000000..71fdf123d5984acab64b0d57448ba5751bfb72f1
--- /dev/null
+++ b/src/routes/credit-card.route.ts
@@ -0,0 +1,110 @@
+import { CreditCardService } from '@/services/credit-card.service'
+import Container from 'typedi'
+import { honoWithJwt } from '..'
+import { zValidator } from '@hono/zod-validator'
+import { creditCardSchemas } from '@/db/schema/credit-card.model'
+import { HttpStatus, createApexError } from '@/services/error.service'
+
+const service = Container.get(CreditCardService)
+
+export const creditCardRouter = honoWithJwt()
+  .post(
+    '/create',
+    zValidator('json', creditCardSchemas.creditCardInputSchema),
+    async (c) => {
+      try {
+        const input = await c.req.valid('json')
+
+        const creditCard =
+          creditCardSchemas.creditCardDtoSchema.parse(
+            await service.create(input)
+          )
+
+        return c.json({ creditCard })
+      } catch (e) {
+        return c.json(
+          createApexError({
+            status: 'error',
+            message: 'could not create credit card',
+            code: HttpStatus.BAD_REQUEST,
+            path: c.req.routePath,
+            suggestion: 'check the input and try again',
+          }),
+          HttpStatus.BAD_REQUEST
+        )
+      }
+    }
+  )
+  .post(
+    '/update',
+    zValidator('json', creditCardSchemas.creditCardUpdateSchema),
+    async (c) => {
+      try {
+        const input = await c.req.valid('json')
+
+        const creditCard =
+          creditCardSchemas.creditCardDtoSchema.parse(
+            await service.update(input)
+          )
+
+        return c.json({ creditCard })
+      } catch (e) {
+        console.log(e)
+
+        return c.json(
+          createApexError({
+            status: 'error',
+            message: 'could not update credit card',
+            code: HttpStatus.BAD_REQUEST,
+            path: c.req.routePath,
+            suggestion: 'check the input and try again',
+          }),
+          HttpStatus.BAD_REQUEST
+        )
+      }
+    }
+  )
+  .post('/delete/:id', async (c) => {
+    try {
+      const id = c.req.param('id')
+
+      const creditCard = creditCardSchemas.creditCardDtoSchema.parse(
+        await service.delete(id)
+      )
+
+      return c.json({ creditCard })
+    } catch (e) {
+      return c.json(
+        createApexError({
+          status: 'error',
+          message: 'could not delete credit card',
+          code: HttpStatus.BAD_REQUEST,
+          path: c.req.routePath,
+          suggestion: 'check the input and try again',
+        }),
+        HttpStatus.BAD_REQUEST
+      )
+    }
+  })
+  .get('/:id', async (c) => {
+    try {
+      const id = c.req.param('id')
+
+      const creditCard = creditCardSchemas.creditCardDtoSchema.parse(
+        await service.find(id)
+      )
+
+      return c.json({ creditCard })
+    } catch (e) {
+      return c.json(
+        createApexError({
+          status: 'error',
+          message: 'could not find credit card',
+          code: HttpStatus.NOT_FOUND,
+          path: c.req.routePath,
+          suggestion: 'are you sure the credit card exists?',
+        }),
+        HttpStatus.NOT_FOUND
+      )
+    }
+  })
diff --git a/src/routes/user.routes.ts b/src/routes/user.routes.ts
index bcf8edc355e0e09d9f7e5ef1959396d25b06ceae..fe9bdc8df8b46822ea48aa828b300cfb9ed78de5 100644
--- a/src/routes/user.routes.ts
+++ b/src/routes/user.routes.ts
@@ -35,9 +35,7 @@ export const userRouter = honoWithJwt()
     zValidator('json', userSchemas.userInputSchema),
     async (c) => {
       try {
-        const input = userSchemas.userInputSchema.parse(
-          await c.req.valid('json')
-        )
+        const input = await c.req.valid('json')
 
         const user = userSchemas.userDtoSchema.parse(
           await service.create(input)
diff --git a/src/services/client.service.ts b/src/services/client.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3622e7030ce4dd951b61ef66477e9c89b42e848c
--- /dev/null
+++ b/src/services/client.service.ts
@@ -0,0 +1,31 @@
+import { ClientRepo } from '@/db/repo/client.repo'
+import type {
+  ClientInput,
+  ClientModel,
+  ClientUpdate,
+} from '@/db/schema/client.model'
+import { Inject, Service } from 'typedi'
+
+@Service()
+export class ClientService {
+  @Inject()
+  private readonly repo: ClientRepo
+
+  async create(client: ClientInput): Promise<ClientModel> {
+    return this.repo.create(client)
+  }
+
+  async update(client: ClientUpdate): Promise<ClientModel> {
+    return this.repo.update(client)
+  }
+
+  async delete(id: ClientModel['id']): Promise<ClientModel> {
+    return this.repo.delete(id)
+  }
+
+  async find(
+    id: ClientModel['id']
+  ): Promise<ClientModel | undefined> {
+    return this.repo.find(id)
+  }
+}
diff --git a/src/services/credit-card.service.ts b/src/services/credit-card.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..62528755105a8197fc857c4ddfa40637b53b36f0
--- /dev/null
+++ b/src/services/credit-card.service.ts
@@ -0,0 +1,35 @@
+import { CreditCardRepo } from '@/db/repo/credit-card.repo'
+import type {
+  CreditCardInput,
+  CreditCardModel,
+  CreditCardUpdate,
+} from '@/db/schema/credit-card.model'
+import { Inject, Service } from 'typedi'
+
+@Service()
+export class CreditCardService {
+  @Inject()
+  private readonly repo: CreditCardRepo
+
+  async create(
+    creditCard: CreditCardInput
+  ): Promise<CreditCardModel> {
+    return this.repo.create(creditCard)
+  }
+
+  async update(
+    creditCard: CreditCardUpdate
+  ): Promise<CreditCardModel> {
+    return this.repo.update(creditCard)
+  }
+
+  async delete(id: CreditCardModel['id']): Promise<CreditCardModel> {
+    return this.repo.delete(id)
+  }
+
+  async find(
+    id: CreditCardModel['id']
+  ): Promise<CreditCardModel | undefined> {
+    return this.repo.find(id)
+  }
+}
diff --git a/src/services/error.service.ts b/src/services/error.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..70488a6cb9840e9e5eb9bd6a38a70cf3eab8e5a9
--- /dev/null
+++ b/src/services/error.service.ts
@@ -0,0 +1,50 @@
+export enum HttpStatus {
+  OK = 200,
+  CREATED = 201,
+  NO_CONTENT = 204,
+  BAD_REQUEST = 400,
+  UNAUTHORIZED = 401,
+  FORBIDDEN = 403,
+  NOT_FOUND = 404,
+  CONFLICT = 409,
+  INTERNAL_SERVER_ERROR = 500,
+  SERVICE_UNAVAILABLE = 503,
+  PAYLOAD_TOO_LARGE = 413,
+}
+
+export type ApexError = {
+  status: 'error' | 'success'
+  statusCode: number
+  error: {
+    code: string
+    message: string
+    // details: string,
+    timestamp: string
+    path: string
+    suggestion: string
+  }
+  // requestId: string,
+  // documentation_url: string
+}
+
+export type ApexErrorInput = {
+  status: 'error' | 'success'
+  code: HttpStatus
+  message: string
+  path: string
+  suggestion: string
+}
+
+export function createApexError(input: ApexErrorInput): ApexError {
+  return {
+    status: input.status,
+    statusCode: input.code,
+    error: {
+      code: `${input.code}`,
+      message: input.message,
+      timestamp: new Date().toISOString(),
+      path: input.path,
+      suggestion: input.suggestion,
+    },
+  }
+}
diff --git a/src/tests/client.test.ts b/src/tests/client.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1e1ea78cde9ec5358b52d8618dd5ef4d869f6653
--- /dev/null
+++ b/src/tests/client.test.ts
@@ -0,0 +1,94 @@
+import { describe, expect, it } from 'bun:test'
+import app from '..'
+import {
+  clientSchemas,
+  type ClientDto,
+  type ClientInput,
+  type ClientUpdate,
+} from '@/db/schema/client.model'
+import { api, token } from './preload-tests'
+import { HttpStatus } from '@/services/error.service'
+
+describe('Tests for client routes', () => {
+  const id = '28222da6-2b0a-49df-a328-0703fed118a2'
+
+  it('should create a new client', async () => {
+    const input: ClientInput = {
+      id,
+      cnpj: '17.579.768/0001-64',
+      name: 'Test Client',
+    }
+
+    const res = await app.request(`${api}/client/create`, {
+      method: 'POST',
+      body: JSON.stringify(input),
+      headers: {
+        'Content-Type': 'application/json',
+        Authorization: token,
+      },
+    })
+
+    expect(res.status).toBe(HttpStatus.OK)
+    const data = (await res.json()) as { client: ClientDto }
+    clientSchemas.clientDtoSchema.parse(data.client)
+  })
+
+  it('should update a client', async () => {
+    const input: ClientUpdate = {
+      id,
+      name: 'Test Client Updated',
+    }
+
+    const res = await app.request(`${api}/client/update`, {
+      method: 'POST',
+      body: JSON.stringify(input),
+      headers: {
+        'Content-Type': 'application/json',
+        Authorization: token,
+      },
+    })
+
+    expect(res.status).toBe(HttpStatus.OK)
+
+    const data = (await res.json()) as { client: ClientDto }
+    clientSchemas.clientDtoSchema.parse(data.client)
+    expect(data.client.name).toBe(input.name!)
+  })
+
+  it('should find a client by id', async () => {
+    const res = await app.request(`${api}/client/${id}`, {
+      headers: {
+        Authorization: token,
+      },
+    })
+
+    expect(res.status).toBe(HttpStatus.OK)
+
+    const data = (await res.json()) as { client: ClientDto }
+    clientSchemas.clientDtoSchema.parse(data.client)
+    expect(data.client.id).toBe(id)
+  })
+
+  it('should delete a client', async () => {
+    const res = await app.request(`${api}/client/delete/${id}`, {
+      method: 'POST',
+      headers: {
+        Authorization: token,
+      },
+    })
+
+    expect(res.status).toBe(HttpStatus.OK)
+
+    const data = (await res.json()) as { client: ClientDto }
+    clientSchemas.clientDtoSchema.parse(data.client)
+    expect(data.client.id).toBe(id)
+
+    const res2 = await app.request(`${api}/client/${id}`, {
+      headers: {
+        Authorization: token,
+      },
+    })
+
+    expect(res2.status).toBe(HttpStatus.NOT_FOUND)
+  })
+})
diff --git a/src/tests/credit-card.test.ts b/src/tests/credit-card.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9245c64f88b2c88c2126fea8a0001b6a75959897
--- /dev/null
+++ b/src/tests/credit-card.test.ts
@@ -0,0 +1,100 @@
+import { describe, expect, it } from 'bun:test'
+import app from '..'
+
+import { api, token } from './preload-tests'
+import { HttpStatus } from '@/services/error.service'
+import {
+  creditCardSchemas,
+  type CreditCardDto,
+  type CreditCardInput,
+  type CreditCardUpdate,
+} from '@/db/schema/credit-card.model'
+
+describe('Tests for credit card routes', () => {
+  const id = '28222da6-2b0a-49df-a328-0703fed118a3'
+  const clientId = 'f1b9b3b4-0b3b-4b3b-8b3b-0b3b4b3b4b3b'
+  const baseUrl = `${api}/credit-card`
+
+  it('should create a new creditCard', async () => {
+    const input: CreditCardInput = {
+      id,
+      clientId,
+      cardholderName: 'Test Cardholder',
+      cardNumber: '1234567890123456',
+      cvv: '123',
+      expirationDate: '2025/12/20',
+    }
+
+    const res = await app.request(`${baseUrl}/create`, {
+      method: 'POST',
+      body: JSON.stringify(input),
+      headers: {
+        'Content-Type': 'application/json',
+        Authorization: token,
+      },
+    })
+
+    expect(res.status).toBe(HttpStatus.OK)
+    const data = (await res.json()) as { creditCard: CreditCardDto }
+    creditCardSchemas.creditCardDtoSchema.parse(data.creditCard)
+  })
+
+  it('should update a credit card', async () => {
+    const input: CreditCardUpdate = {
+      id,
+      cardholderName: 'Test Cardholder Updated',
+    }
+
+    const res = await app.request(`${baseUrl}/update`, {
+      method: 'POST',
+      body: JSON.stringify(input),
+      headers: {
+        'Content-Type': 'application/json',
+        Authorization: token,
+      },
+    })
+
+    expect(res.status).toBe(HttpStatus.OK)
+
+    const data = (await res.json()) as { creditCard: CreditCardDto }
+    creditCardSchemas.creditCardDtoSchema.parse(data.creditCard)
+    expect(data.creditCard.cardholderName).toBe(input.cardholderName!)
+  })
+
+  it('should find a credit card by id', async () => {
+    const res = await app.request(`${baseUrl}/${id}`, {
+      headers: {
+        Authorization: token,
+      },
+    })
+
+    expect(res.status).toBe(HttpStatus.OK)
+
+    const data = (await res.json()) as { creditCard: CreditCardDto }
+    creditCardSchemas.creditCardDtoSchema.parse(data.creditCard)
+    expect(data.creditCard.id).toBe(id)
+  })
+
+  it('should delete a credit card', async () => {
+    const res = await app.request(`${baseUrl}/delete/${id}`, {
+      method: 'POST',
+      headers: {
+        Authorization: token,
+      },
+    })
+
+    expect(res.status).toBe(HttpStatus.OK)
+
+    const data = (await res.json()) as { creditCard: CreditCardDto }
+    creditCardSchemas.creditCardDtoSchema.parse(data.creditCard)
+    expect(data.creditCard.id).toBe(id)
+
+    const res2 = await app.request(`${baseUrl}/${id}`, {
+      headers: {
+        Authorization: token,
+      },
+    })
+
+    expect(res2.status).toBe(HttpStatus.NOT_FOUND)
+  })
+})
diff --git a/src/tests/preload-tests.ts b/src/tests/preload-tests.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f8838f56d966f5671cb426f6e3b7265455c9c1e6
--- /dev/null
+++ b/src/tests/preload-tests.ts
@@ -0,0 +1,8 @@
+import 'reflect-metadata'
+
+console.log('preloaded for tests')
+
+export const api = 'http://localhost:3000/api'
+
+export const token =
+  'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImZlNzcwMWJjLWNhZDItNDNkYi05ZjFiLWE3ZDhjM2I1Zjc0YiIsInVzZXJuYW1lIjoiYWRtaW4ifQ.Cd8ixLFseKLRidLTpBfHA1QLolwBFO2pzXHq9UtclWk'