Psyter Tahoon (Shared) API - Detailed Structure

Project: Tahoon Shared API (.NET 8)
Technology: ASP.NET Core Web API 8.0, JWT Authentication, Entity Framework
Purpose: Third-party integration API for external organizations (Tahoon platform)
Last Updated: November 5, 2025


📁 Root Structure

Tahoon_API/
├── PsyterSharedAPI/               # Main API project
│   ├── Controllers/               # API controllers
│   ├── Data/                      # Data layer
│   │   ├── Model/                 # Request/Response models
│   │   └── Repositories/          # Data access layer
│   ├── Helpers/                   # Utility classes
│   ├── ActionFilters/             # Custom attributes
│   ├── Extensions/                # Extension methods
│   ├── Program.cs                 # Application entry point
│   ├── appsettings.json           # Configuration
│   ├── firebase-adminsdk.json     # FCM config
│   └── PsyterSharedAPI.csproj     # Project file
├── PsyterSharedAPI.sln            # Solution file
├── azure-pipelines.yml            # CI/CD pipeline
├── .gitignore                     # Git ignore rules
└── .git/                          # Git repository

🎯 Project Overview

Purpose

Third-party integration API designed specifically for external organizations (like Tahoon) to:
- Integrate: Connect external systems to Psyter platform
- Register Users: Create patient accounts for partner organizations
- Book Sessions: Schedule therapy sessions programmatically
- Manage Bookings: Cancel/reschedule appointments
- Access Providers: Get available care providers and schedules
- Secure Access: Organization-based authentication and authorization

Key Differences from Main API

Main API vs Tahoon API:

Feature Main API Tahoon API
Users Direct patients/providers Partner organizations
Authentication User credentials Organization API key + JWT
Authorization User-level permissions Organization-level access
Purpose Full platform features Booking & integration only
User Registration Self-registration Programmatic registration
Payment Direct payment gateway Charity/organization credits
Technology .NET Framework 4.7.2 .NET 8

Architecture

.NET 8 Web API:
- RESTful API: HTTP/HTTPS endpoints
- JWT Authentication: Token-based security
- Repository Pattern: Separation of concerns
- Dependency Injection: Built-in IoC container
- Swagger/OpenAPI: API documentation
- Action Filters: Request validation & security


📦 Dependencies

PsyterSharedAPI.csproj

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <!-- Firebase Push Notifications -->
    <PackageReference Include="Google.Apis.FirebaseCloudMessaging.v1" Version="1.70.0.3813" />

    <!-- JWT Authentication -->
    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.18" />

    <!-- JSON Serialization -->
    <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />

    <!-- API Documentation -->
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />

    <!-- Database Access -->
    <PackageReference Include="System.Data.SqlClient" Version="4.9.0" />

    <!-- JWT Token Generation -->
    <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.13.0" />
  </ItemGroup>
</Project>

Core Components

ASP.NET Core 8.0:
- Built-in dependency injection
- Middleware pipeline
- Minimal API support
- Enhanced performance

JWT Bearer Authentication:
- Token-based security
- Claims-based authorization
- Organization-level access control

Firebase Cloud Messaging:
- Push notifications for bookings
- Multi-platform support (Android/iOS)

Swagger/OpenAPI:
- Interactive API documentation
- Try-it-out functionality
- Authentication testing


⚙️ Configuration

appsettings.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "AppBasePath": "https://dvx.innotech-sa.com/Psyter/Master/TuhoonAPIs",

  "Jwt": {
    "Key": "7955BF0A-8507-4214-B494-8B2B5F1BF150",
    "Issuer": "psyter.com",
    "Audience": "psyter_client"
  },

  "ConnectionStrings": {
    "PsyterDatabase": "[Encrypted]",
    "SchedulingDatabase": "[Encrypted]"
  },

  "CommandTimeout": "30",

  "SecuritySettings": {
    "AESKey": "pH2uJjFtaE4n+Kk3QfCNrX4lZkZcPbqP5gVZAp1o0P8=",
    "AESIV": "q6JxgUuToRnQmTnOKGh3Nw==",
    "PassPhrase": "55C9F5A8-17B8-4783-ABB1-D9AC7C3CF9BB",
    "Salt": "2GlHRj2MxxxC2Dnn",
    "Vector": "8WhO95QaRasSxsfh",
    "EncryptionPassword": "Password*1"
  }
}

Security Settings

Encryption:
- AES Key/IV: For AES encryption
- PassPhrase: For secure hash generation
- Salt/Vector: For password hashing
- EncryptionPassword: API access password

JWT Configuration:
- Key: Symmetric key for token signing
- Issuer: psyter.com
- Audience: psyter_client
- Expiration: 24 hours

Database:
- Two connection strings (encrypted)
- PsyterDatabase: Main database
- SchedulingDatabase: Scheduling system


🔐 Authentication Flow

1. Obtain Access Token

Endpoint: POST /api/auth/token

Request:

POST /api/auth/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded

access_key=YOUR_ORGANIZATION_KEY&grant_type=password

Process:
1. Validate access_key from database
2. Check organization exists and is active
3. Generate JWT token with organization claims
4. Return access token

Response:

{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "token_type": "bearer",
    "expires_in": 86400
}

Token Claims:

{
    "sub": "123",              // Organization ID
    "OrganizationId": "123",   // Organization ID
    "SharedAPIKey": "KEY",     // API key
    "jti": "unique-guid",      // Token ID
    "iat": 1699200000,         // Issued at
    "exp": 1699286400          // Expires at
}

2. Use Token in API Calls

Authorization Header:

GET /api/careprovider/getcareproviderslistwithschedule HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

Token Validation:
- Verify signature with JWT key
- Check expiration
- Extract organization ID
- Validate organization access


📡 API Controllers

Total Controllers: 5

  1. AuthController - Authentication
  2. UserController - User management
  3. CareProviderController - Provider listing
  4. SessionBookingController - Booking operations
  5. SecurityController - Encryption utilities (internal)

1️⃣ AuthController

Route: /api/auth

POST /api/auth/token

Purpose: Obtain JWT access token

Authentication: None (public endpoint)

Request:

Content-Type: application/x-www-form-urlencoded

access_key=YOUR_ORG_KEY&grant_type=password

Response:

{
    "access_token": "eyJhbGciOiJIUzI1...",
    "token_type": "bearer",
    "expires_in": 86400
}

Error Responses:
- 401 Unauthorized - Invalid credentials


2️⃣ UserController

Route: /api/user
Authentication: Required ([Authorize])

POST /api/user/register

Purpose: Register new organization user (patient)

Security:
- JWT authentication required
- Secure hash validation ([ValidateSecureHash])
- Anti-XSS validation ([ValidateAntiXSS])

Request:

{
    "ReferenceId": "EXT-12345",
    "Name": "John Smith",
    "DOB": "1990-05-15",
    "GenderType": 1,
    "SecureHash": "computed_hash"
}

SecureHash Calculation:

Hash = SHA256(ReferenceId + Name + DOB + GenderType + PassPhrase)

Process:
1. Validate secure hash
2. Extract organization ID from JWT token
3. Check if user already exists (by ReferenceId)
4. Create user account in Psyter system
5. Link user to organization
6. Return encrypted user ID

Response:

{
    "Status": 1,
    "Reason": "Success",
    "Message": "User registered successfully",
    "Data": {
        "UserLoginInfoId": 123,
        "UserId": "encrypted_user_id",
        "ReferenceId": "EXT-12345",
        "Name": "John Smith"
    }
}

GET /api/user/getassessmentquestions

Purpose: Get screening questions for assessment

Response:

{
    "Status": 1,
    "Data": [
        {
            "ScreeningQuestionId": 1,
            "Question": "How often do you feel anxious?",
            "QuestionType": 1,
            "Options": [
                {"OptionId": 1, "OptionText": "Never"},
                {"OptionId": 2, "OptionText": "Sometimes"},
                {"OptionId": 3, "OptionText": "Often"},
                {"OptionId": 4, "OptionText": "Always"}
            ]
        }
    ]
}

POST /api/user/submituserassessmentquestions

Purpose: Submit user screening assessment

Request:

{
    "UserId": "encrypted_user_id",
    "ScreeningResult": "Moderate",
    "UserScreeningAnswers": [
        {
            "ScreeningQuestionId": 1,
            "CatScreeningQuetionOptionId": 3,
            "AnswerText": null
        }
    ]
}


3️⃣ CareProviderController

Route: /api/careprovider
Authentication: Required

POST /api/careprovider/getcareproviderslistwithschedule

Purpose: Get filtered list of providers with available schedules

Request:

{
    "UserId": "encrypted_user_id",
    "ScheduleDate": "2025-11-10",
    "GMTTimeDiffrenceHours": 3,
    "ApplyFilter": true,
    "FilterCriteria": {
        "GenderType": 2,
        "SpecialityId": 5,
        "LanguageId": 1,
        "MinExperience": 5,
        "MaxFees": 300
    }
}

Process:
1. Validate organization and user (if provided)
2. Get available schedules for date
3. Apply filters (gender, specialty, language, etc.)
4. Calculate available time slots
5. Sort by availability and match criteria

Response:

{
    "Status": 1,
    "Data": {
        "CareProvidersList": [
            {
                "UserLoginInfoId": 456,
                "FullName": "Dr. Sarah Ahmed",
                "FirstNamePLang": "Dr. Sarah",
                "LastNamePLang": "Ahmed",
                "GenderType": 2,
                "Speciality": "Clinical Psychologist",
                "Experience": 10,
                "ConsultationFee": 250,
                "ProfileImage": "/path/to/image.jpg",
                "Rating": 4.8,
                "TotalRatings": 120,
                "Languages": ["Arabic", "English"],
                "AvailableScheduleHoursList": [
                    {
                        "Hour": 10,
                        "IsAvailable": true,
                        "SlotDuration": 60
                    }
                ],
                "AvailableSlotsList": [
                    {
                        "StartTime": "10:00",
                        "EndTime": "11:00",
                        "IsAvailable": true
                    }
                ]
            }
        ]
    }
}

POST /api/careprovider/getcareproviderschedule

Purpose: Get specific provider’s schedule for a date

Request:

{
    "CareProviderId": "encrypted_provider_id",
    "CareProviderId_Decrypted": 456,
    "UserId": "encrypted_user_id",
    "UserId_Decrypted": 123,
    "ScheduleDate": "2025-11-10",
    "GMTTimeDiffrenceHours": 3
}

Response:

{
    "AvailableHoursList": [
        {"Hour": 10, "IsAvailable": true},
        {"Hour": 11, "IsAvailable": false},
        {"Hour": 14, "IsAvailable": true}
    ],
    "AvailableHoursSlots": [
        {
            "ServiceProviderId": 456,
            "StartTime": "10:00",
            "EndTime": "11:00",
            "IsAvailable": true,
            "AvailabilityId": 789
        }
    ],
    "SlotDurationSetting": {
        "ServiceProviderId": 456,
        "SlotDuration": 60,
        "SlotDurationType": 1
    }
}

POST /api/careprovider/getcareprovidersprofiledata

Purpose: Get detailed profile of care provider

Request:

{
    "CareProviderId": "encrypted_provider_id"
}

Response:

{
    "Status": 1,
    "Data": {
        "UserLoginInfoId": 456,
        "FullName": "Dr. Sarah Ahmed",
        "Bio": "Experienced clinical psychologist...",
        "Education": ["PhD Psychology", "MSc Clinical Psychology"],
        "Certifications": ["CBT Specialist", "EMDR Certified"],
        "Experience": 10,
        "Specialities": ["Anxiety", "Depression", "PTSD"],
        "Languages": ["Arabic", "English"],
        "ConsultationFee": 250,
        "Rating": 4.8,
        "TotalRatings": 120,
        "Reviews": [...]
    }
}

GET /api/careprovider/getcataloguedataforfilters

Purpose: Get filter options (specialties, languages, etc.)

Response:

{
    "Status": 1,
    "Data": {
        "Specialities": [
            {"Id": 1, "Name": "Clinical Psychology"},
            {"Id": 2, "Name": "Marriage Counseling"}
        ],
        "Languages": [
            {"Id": 1, "Name": "Arabic"},
            {"Id": 2, "Name": "English"}
        ],
        "GenderTypes": [
            {"Id": 1, "Name": "Male"},
            {"Id": 2, "Name": "Female"}
        ]
    }
}


4️⃣ SessionBookingController

Route: /api/sessionbooking
Authentication: Required
Security: Anti-XSS validation

POST /api/sessionbooking/booksession

Purpose: Book therapy session for organization user

Security:
- JWT authentication
- Secure hash validation
- Anti-XSS protection

Request:

{
    "UserId": "encrypted_user_id",
    "UserId_Decrypted": 123,
    "CareProviderId": "encrypted_provider_id",
    "CareProviderId_Decrypted": 456,
    "SlotDate": "2025-11-10",
    "SlotStartTime": "10:00",
    "SlotEndTime": "11:00",
    "SlotAvailabilityId": 789,
    "ApplicationMultiSlotId": "encrypted_slot_id",
    "ApplicationMultiSlotId_Decrypted": 1,
    "CareProviderSlotDurationId": "encrypted_duration_id",
    "CareProviderSlotDurationId_Decrypted": 5,
    "CatCommunicationTypeId": 3,
    "IsBookingFromMobile": false,
    "BookingPlatformId": 3,
    "ReferenceId": "EXT-12345",
    "Name": "John Smith",
    "DOB": "1990-05-15",
    "GenderType": 1,
    "SecureHash": "computed_hash"
}

Process:
1. User Validation:
- If UserId provided: Validate user belongs to organization
- If no UserId: Auto-register user with ReferenceId/Name/DOB

  1. Slot Validation:
    - Check slot availability
    - Verify provider schedule
    - Confirm time slot not booked

  2. Booking Creation:
    - Create booking in scheduling system
    - Generate VideoSDK meeting ID
    - Set booking status to “Confirmed”
    - No payment required (charity/organization credits)

  3. Notifications:
    - Send FCM notification to provider
    - Create booking confirmation
    - Schedule reminders

Response:

{
    "Status": 1,
    "Reason": "Success",
    "Message": "Session booked successfully",
    "Data": {
        "MeetingId": "abc-123-def-456",
        "BookingId": "encrypted_booking_id"
    }
}

Meeting ID:
- Generated via VideoSDK API
- Used for video call session
- Stored in database for reference

POST /api/sessionbooking/cancelbooking

Purpose: Cancel scheduled booking

Security:
- JWT authentication
- Secure hash validation
- Anti-XSS protection

Request:

{
    "BookingId": "encrypted_booking_id",
    "BookingId_Decrypted": 999,
    "CareProviderId": "encrypted_provider_id",
    "CareProviderId_Decrypted": 456,
    "UserId": "encrypted_user_id",
    "UserId_Decrypted": 123,
    "SecureHash": "computed_hash"
}

Process:
1. Validate user and organization
2. Check booking exists and is cancellable
3. Update booking status to “Cancelled”
4. Refund organization credits
5. Notify provider of cancellation
6. Update schedule availability

Response:

{
    "Status": 1,
    "Reason": "Success",
    "Message": "Booking cancelled successfully",
    "Data": {
        "RefundAmount": 0,
        "BookingStatus": "Cancelled"
    }
}


5️⃣ SecurityController

Route: /api/security
Purpose: Internal encryption/decryption utilities
Hidden from API documentation: [ApiExplorerSettings(IgnoreApi = true)]

POST /api/security/encryptText

Purpose: Encrypt plain text (for testing)

Authentication: Password required

Request:

{
    "PlainText": "123",
    "AuthPssword": "Password*1"
}

Response:

{
    "EncryptedString": "CYmF%2FyAGJuky51QOyaxql%2FwHXg8ZJXcG..."
}

POST /api/security/decryptText

Purpose: Decrypt encrypted text (for testing)

Request:

{
    "EncryptedText": "CYmF%2FyAGJuky51QOyaxql%2FwHXg8ZJXcG...",
    "AuthPssword": "Password*1"
}

Response:

{
    "DecryptedString": "123"
}


🔧 Helpers

VideoSDKHelper.cs

Purpose: Integration with VideoSDK for video calls

Key Methods:

GenerateToken()

public async Task<string> GenerateToken(string apiKey, string secretKey)

- Generate JWT token for VideoSDK API
- Claims: apiKey, permissions (allow_join, allow_mod)
- Expiration: 24 hours

CreateMeetingAsync()

public async Task<BaseResponse> CreateMeetingAsync(string token, string customMeetingId)

- Create video meeting room
- Optional: Enable auto-recording with transcription
- Returns meeting ID

Configuration:
- API endpoint stored in database
- API key/secret from config
- Recording enabled/disabled per organization

FCMNotificationHelper.cs

Purpose: Send push notifications via Firebase Cloud Messaging

Key Methods:

SendFCMMessageAsync()

public async Task<bool> SendFCMMessageAsync(
    string topic, 
    string title, 
    string titleSLang, 
    string body, 
    string bodySLang, 
    object template, 
    bool saveToDB)

Features:
- Multi-language support (Primary + Arabic)
- Topic-based messaging
- Save to database for history
- Android/iOS platform support

Topics:
- android_doctor_{providerId}~ - Android providers
- ios_doctor_{providerId}~ - iOS providers
- android_patient_{patientId}~ - Android patients
- ios_patient_{patientId}~ - iOS patients

Notification Types:
- New booking
- Booking cancelled
- Booking reminder (30 min, 1 hour, 1 day)
- Session starting soon

SecurityHelper.cs

Purpose: Encryption/decryption utilities

Key Methods:

EncryptString()

public string EncryptString(string plainText)

- AES encryption
- Uses AESKey and AESIV from config
- URL-safe encoding

DecryptString()

public string DecryptString(string encryptedText)

- AES decryption
- URL-safe decoding

EncryptId() / DecryptId()

public string EncryptId(string id)
public long DecryptId(string encryptedId)

- Encrypt/decrypt database IDs
- Used in API requests/responses
- Prevents ID enumeration

ComputeSecureHash()

public string ComputeSecureHash(params string[] values)

- SHA256 hash generation
- Used for request validation
- Combines values with passphrase

XmlHelper.cs

Purpose: Convert objects to XML for stored procedures

Key Methods:

ObjectToXml()

public static string ObjectToXml<T>(T obj)

- Serialize object to XML string
- Used for complex data in stored procedures
- Handles nested objects and lists


🛡️ Action Filters

ValidateSecureHashAttribute

Purpose: Validate secure hash in request

Usage: [ValidateSecureHash]

Process:
1. Extract SecureHash from request
2. Extract request values
3. Compute expected hash
4. Compare with provided hash
5. Reject if mismatch

Example:

// Request
{
    "ReferenceId": "EXT-123",
    "Name": "John",
    "SecureHash": "abc123..."
}

// Validation
expectedHash = SHA256(ReferenceId + Name + PassPhrase)
if (expectedHash != providedHash) {
    return BadRequest("Invalid secure hash");
}

ValidateAntiXSSAttribute

Purpose: Prevent XSS attacks

Usage: [ValidateAntiXSS]

Process:
1. Scan all request parameters
2. Check for HTML/script tags
3. Validate against XSS patterns
4. Reject suspicious requests

Patterns Detected:
- <script>
- javascript:
- onerror=
- <iframe>
- SQL injection attempts

EncryptedModelBinderProvider

Purpose: Auto-decrypt encrypted IDs

Usage: Automatic via [FromBody]

Process:
1. Detects properties ending with _Decrypted
2. Finds corresponding encrypted property
3. Auto-decrypts value
4. Populates decrypted property

Example:

public class BookingRequest
{
    public string UserId { get; set; }           // Encrypted
    public long UserId_Decrypted { get; set; }   // Auto-populated
}

AuthOperationFilter

Purpose: Add authentication to Swagger docs

Usage: Automatic

Result: Swagger UI shows lock icon on protected endpoints


🗄️ Data Repositories

Total Repositories: 7

  1. AuthRepository - Authentication
  2. UserRepository - User management
  3. CareProviderRepository - Provider data
  4. SchedulingRepository - Schedule management
  5. SessionBookingRepository - Booking operations
  6. CommonRepository - Shared utilities
  7. BaseRepository - Base data access

BaseRepository

Purpose: Base class for all repositories

Key Methods:
- ExecuteStoredProcedure() - Execute SP
- GetConnection() - Get DB connection
- ConvertToObject<T>() - Map DataRow to object

AuthRepository

Stored Procedures:
- SHARED_API_AUTHENTICATE - Validate organization key

UserRepository

Stored Procedures:
- SHARED_API_REGISTER_ORGANIZATION_USER - Register user
- SHARED_API_VALIDATE_ORGANIZATION_USER - Validate user
- GET_SCREENING_QUESTIONS - Get assessment questions
- SAVE_USER_SCREENING - Save assessment answers

CareProviderRepository

Stored Procedures:
- SHARED_API_GET_CARE_PROVIDERS_LIST_FOR_GUEST - List providers (guest)
- SHARED_API_GET_CARE_PROVIDERS_LIST_FOR_LOGIN_USER - List providers (user)
- GET_CARE_PROVIDER_PROFILE - Provider details
- GET_CATALOGUE_DATA_FOR_FILTERS - Filter options

SchedulingRepository

Stored Procedures:
- GET_NEXT_HOURLY_SCHEDULE_FOR_CARE_PROVIDERS - Available schedules
- GET_SCHEDULE_BY_HOUR - Specific hour validation
- SAVE_SCHEDULE_BOOKING - Create booking
- UPDATE_BOOKING_STATUS - Update status

SessionBookingRepository

Stored Procedures:
- SHARED_API_SAVE_BOOKING_ORDER_PAY_FOR_DATA - Save booking
- SHARED_API_GET_BOOKING_DETAILS_FOR_REFUND - Get refund info
- SHARED_API_REFUND_BOOKING_PAYMENT - Process refund
- SHARED_API_GET_BOOKING_DETAILS - Get booking details

CommonRepository

Stored Procedures:
- APP_CONFIG_BY_GROUPID - Get app config
- GET_USER_REMINDERS_LIST - Get reminders
- SAVE_VIDEOSDK_MEETING_ID - Store meeting ID


🔄 Typical Booking Flow

Complete Session Booking Process

1. Organization Authentication:

POST /api/auth/token
Content-Type: application/x-www-form-urlencoded

access_key=ORG_KEY_123&grant_type=password

Response:

{
    "access_token": "eyJhbGciOiJI...",
    "token_type": "bearer",
    "expires_in": 86400
}


2. Get Available Providers:

POST /api/careprovider/getcareproviderslistwithschedule
Authorization: Bearer eyJhbGciOiJI...
Content-Type: application/json

{
    "ScheduleDate": "2025-11-10",
    "GMTTimeDiffrenceHours": 3,
    "ApplyFilter": true,
    "FilterCriteria": {
        "GenderType": 2,
        "SpecialityId": 5
    }
}

Response:

{
    "Status": 1,
    "Data": {
        "CareProvidersList": [
            {
                "UserLoginInfoId": 456,
                "FullName": "Dr. Sarah Ahmed",
                "AvailableSlotsList": [
                    {
                        "StartTime": "10:00",
                        "EndTime": "11:00",
                        "AvailabilityId": 789
                    }
                ]
            }
        ]
    }
}


3. Book Session:

POST /api/sessionbooking/booksession
Authorization: Bearer eyJhbGciOiJI...
Content-Type: application/json

{
    "ReferenceId": "EXT-12345",
    "Name": "John Smith",
    "DOB": "1990-05-15",
    "GenderType": 1,
    "CareProviderId": "encrypted_456",
    "CareProviderId_Decrypted": 456,
    "SlotDate": "2025-11-10",
    "SlotStartTime": "10:00",
    "SlotEndTime": "11:00",
    "SlotAvailabilityId": 789,
    "ApplicationMultiSlotId_Decrypted": 1,
    "CareProviderSlotDurationId_Decrypted": 5,
    "CatCommunicationTypeId": 3,
    "SecureHash": "computed_hash"
}

Process:
1. Register user (if new) or validate existing
2. Validate slot availability
3. Create booking in scheduling system
4. Generate VideoSDK meeting ID
5. Update booking status to “Confirmed”
6. Send FCM notification to provider
7. Create booking reminders

Response:

{
    "Status": 1,
    "Reason": "Success",
    "Message": "Session booked successfully",
    "Data": {
        "MeetingId": "abc-123-def-456",
        "BookingId": "encrypted_999"
    }
}


4. Provider Receives Notification:

Topic: android_doctor_456~
Title: "New Appointment Booked"
Body: "John Smith has booked an appointment with you on 2025-11-10 10:00 AM"
Data: {
    "NotificationType": 1,
    "SlotBookingId": 999,
    "VideoSDKMeetingId": "abc-123-def-456",
    ...
}


5. Session Start (Provider App):
- Provider opens app
- Sees booking notification
- Joins video call using MeetingId
- Video call via VideoSDK


6. Session End (Optional Cancel):

POST /api/sessionbooking/cancelbooking
Authorization: Bearer eyJhbGciOiJI...
Content-Type: application/json

{
    "BookingId": "encrypted_999",
    "BookingId_Decrypted": 999,
    "CareProviderId": "encrypted_456",
    "CareProviderId_Decrypted": 456,
    "UserId": "encrypted_123",
    "UserId_Decrypted": 123,
    "SecureHash": "computed_hash"
}

Process:
1. Validate booking
2. Update status to “Cancelled”
3. Refund organization credits
4. Notify provider
5. Free up slot


📊 Data Models

Request Models

AuthRequest:

public class AuthRequest
{
    public string AccessKey { get; set; }
    public string GrantType { get; set; }
}

UserRegistrationRequest:

public class UserRegistrationRequest
{
    public string ReferenceId { get; set; }
    public string Name { get; set; }
    public DateTime DOB { get; set; }
    public int GenderType { get; set; }
    public string SecureHash { get; set; }
}

CareProviderFilterCriteria:

public class CareProviderFilterCriteria
{
    public string UserId { get; set; }
    public string ScheduleDate { get; set; }
    public int GMTTimeDiffrenceHours { get; set; }
    public bool ApplyFilter { get; set; }
    public int? GenderType { get; set; }
    public long? SpecialityId { get; set; }
    public long? LanguageId { get; set; }
    public int? MinExperience { get; set; }
    public decimal? MaxFees { get; set; }
}

BookOrderRequest:

public class BookOrderRequest
{
    public string UserId { get; set; }
    public long UserId_Decrypted { get; set; }
    public string CareProviderId { get; set; }
    public long CareProviderId_Decrypted { get; set; }
    public string SlotDate { get; set; }
    public string SlotStartTime { get; set; }
    public string SlotEndTime { get; set; }
    public long SlotAvailabilityId { get; set; }
    public string ApplicationMultiSlotId { get; set; }
    public long ApplicationMultiSlotId_Decrypted { get; set; }
    public string CareProviderSlotDurationId { get; set; }
    public long CareProviderSlotDurationId_Decrypted { get; set; }
    public int CatCommunicationTypeId { get; set; }
    public bool IsBookingFromMobile { get; set; }
    public int BookingPlatformId { get; set; }
    public string ReferenceId { get; set; }
    public string Name { get; set; }
    public DateTime? DOB { get; set; }
    public int? GenderType { get; set; }
    public string SecureHash { get; set; }
}

Response Models

BaseResponse:

public class BaseResponse
{
    public int Status { get; set; }
    public ResponseReason Reason { get; set; }
    public string Message { get; set; }
    public object Data { get; set; }
}

CareProvidersListResponse:

public class CareProvidersListResponse
{
    public List<CareProviderInfo> CareProvidersList { get; set; }
}

public class CareProviderInfo
{
    public long UserLoginInfoId { get; set; }
    public string FullName { get; set; }
    public string FirstNamePLang { get; set; }
    public string LastNamePLang { get; set; }
    public string FirstNameSLang { get; set; }
    public string LastNameSLang { get; set; }
    public int GenderType { get; set; }
    public string Speciality { get; set; }
    public int Experience { get; set; }
    public decimal ConsultationFee { get; set; }
    public string ProfileImage { get; set; }
    public decimal Rating { get; set; }
    public int TotalRatings { get; set; }
    public List<string> Languages { get; set; }
    public List<AvailableHour> AvailableScheduleHoursList { get; set; }
    public List<AvailableSlot> AvailableSlotsList { get; set; }
    public SlotDuration SlotDurationType { get; set; }
}


🔒 Security Features

Multi-Layer Security

1. API Key Authentication:
- Organization-level access key
- Validated against database
- Must be active organization

2. JWT Token:
- Bearer token authentication
- 24-hour expiration
- Claims-based authorization
- Organization ID embedded

3. Secure Hash Validation:
- SHA256 hash of request parameters
- Prevents parameter tampering
- Validates request integrity

4. ID Encryption:
- All entity IDs encrypted
- Prevents ID enumeration
- AES encryption

5. Anti-XSS Protection:
- Validates all input parameters
- Rejects HTML/script tags
- Prevents code injection

6. Organization Isolation:
- Users belong to organizations
- Can only access own users
- No cross-organization access


🚀 Deployment

Azure DevOps Pipeline

File: azure-pipelines.yml

Pipeline Steps:

  1. Stop Application Pool:

    Stop-WebAppPool -Name "psyter_tuhoon"
    

  2. Restore NuGet Packages:

    nuget restore **/*.sln
    

  3. Install .NET 8 SDK:

    UseDotNet@2:
      version: '8.0.x'
    

  4. Build Project:

    dotnet build --configuration Release
    

  5. Publish:

    dotnet publish --configuration Release --output $(Build.ArtifactStagingDirectory)
    

  6. Create Artifact:
    - Zip published files
    - Store in artifact directory

  7. Copy to Deployment:

    Source: $(Build.ArtifactStagingDirectory)
    Target: D:\ROOT\Development\Psyter\Master\agent\
    

  8. Extract:

    Extract: D:\ROOT\Development\Psyter\Master\agent\*.zip
    Destination: D:\ROOT\Development\Psyter\Master\TuhoonAPIs
    

  9. Start Application Pool:

    Start-WebAppPool -Name "psyter_tuhoon"
    

Deployment Target:

D:\ROOT\Development\Psyter\Master\TuhoonAPIs

IIS Configuration:
- App Pool: psyter_tuhoon
- .NET Version: .NET 8.0
- Pipeline Mode: Integrated
- URL: https://dvx.innotech-sa.com/Psyter/Master/TuhoonAPIs


📚 API Documentation (Swagger)

Access Swagger UI

URL: https://dvx.innotech-sa.com/Psyter/Master/TuhoonAPIs/swagger

Features:
- Interactive API testing
- Request/response examples
- Try-it-out functionality
- Authentication testing
- Schema documentation

Swagger Configuration

Program.cs:

builder.Services.AddSwaggerGen(options =>
{
    options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
    {
        Name = "Authorization",
        Type = SecuritySchemeType.Http,
        Scheme = "bearer",
        BearerFormat = "JWT",
        In = ParameterLocation.Header,
        Description = "Enter JWT: Bearer eyJhbGciOiJI..."
    });

    options.OperationFilter<AuthOperationFilter>();
});

Swagger Features:
- Automatic endpoint discovery
- JWT authentication UI
- Request validation
- Response examples
- Error documentation


🔄 Integration Patterns

Pattern 1: Guest Booking (No Pre-registration)

Use Case: External organization books session for new user

1. Get Token (/api/auth/token)
2. Get Providers (/api/careprovider/getcareproviderslistwithschedule)
3. Book Session (/api/sessionbooking/booksession)
   - Provide ReferenceId, Name, DOB
   - System auto-registers user
   - Returns BookingId + MeetingId

Pattern 2: Registered User Booking

Use Case: External organization books for existing user

1. Get Token
2. Register User (/api/user/register)
   - Store UserId
3. Get Providers
4. Book Session
   - Use stored UserId
   - No need for Name/DOB

Pattern 3: Provider Search with Filters

Use Case: Find specific type of provider

1. Get Token
2. Get Filter Options (/api/careprovider/getcataloguedataforfilters)
3. Get Providers with Filters
   - Apply GenderType, Speciality, Language, etc.
   - Get only available slots for date

📊 Differences from Main API

Technology

Feature Main API Tahoon API
Framework .NET Framework 4.7.2 .NET 8
API Style Web API 2 ASP.NET Core
Auth OAuth 2.0 JWT Bearer
DI Autofac Built-in
Swagger Swashbuckle 5 Swashbuckle 6

Functionality

Feature Main API Tahoon API
Users All users Organization users only
Registration Full profile Minimal (ReferenceId/Name/DOB)
Payment Full payment flow No payment (charity credits)
Booking All booking types Session booking only
Profile Full management Read-only
Messaging Full chat Not included
Notifications Via NodeServer Direct FCM

Security

Feature Main API Tahoon API
Auth User credentials Organization API key
Scope User-level Organization-level
Validation Standard Secure hash required
IDs Plain Encrypted
XSS Manual checks Automatic filter

🎯 Key Benefits

For External Organizations

Easy Integration: RESTful API with clear documentation
Secure Access: Organization-level authentication
Auto User Registration: No pre-registration needed
Zero Payment Hassle: Uses organization credits
Real-time Availability: Check provider schedules instantly
Video Calls Included: VideoSDK integration built-in
Push Notifications: Automatic FCM notifications
Swagger Documentation: Interactive API testing

For Psyter Platform

Revenue: Partner organizations pay for credits
Scale: Support multiple organizations
Isolation: Organization data separation
Flexibility: Different rules per organization
Tracking: Reference IDs link to external systems
Modern Tech: .NET 8 performance benefits


📈 Performance Considerations

Optimization Strategies

1. Connection Pooling:
- SQL Server connection pool
- Reuse database connections
- Configurable timeout

2. Async/Await:
- All repository methods async
- Non-blocking I/O operations
- Better scalability

3. Caching:
- Cache filter options (specialties, languages)
- Cache organization data
- Reduce database queries

4. Minimal Data:
- Only return necessary fields
- Pagination support ready
- Compressed responses


🔧 Maintenance

Configuration Updates

Update JWT Key:

"Jwt": {
    "Key": "NEW_KEY_HERE"
}

Update Organization Access:

UPDATE Organizations
SET SharedAPIKey = 'NEW_KEY',
    IsActive = 1
WHERE OrganizationId = 123

Monitoring

Health Checks:
- Database connectivity
- VideoSDK API availability
- FCM service status
- Response times

Logs:
- ASP.NET Core logging
- IIS logs
- Application Insights (if configured)


END OF TAHOON API DOCUMENTATION


Completion Status:
- ✅ Android Client (COMPLETED)
- ✅ AndroidCareProvider (COMPLETED)
- ✅ APIs - Part 1 (COMPLETED)
- ✅ APIs - Part 2 (COMPLETED)
- ✅ Media API (COMPLETED)
- ✅ NodeServer (COMPLETED)
- ✅ Tahoon_API (COMPLETED)
- ⏭️ Web (NEXT)
- Pending: WindowsService, IOSCareProvider