RahalCorporate
PoliciesReference

API Reference

Policy management API endpoints

Policy API Reference

This reference documents the API endpoints for policy management.

Base URL

/api/v1/policies

Authentication

All endpoints require authentication via JWT token in the Authorization header:

Authorization: Bearer <token>

Endpoints

Evaluate Policy

Evaluate a flight and/or hotel against the user's effective policy.

POST /api/v1/policies/evaluate

Request Body:

{
  "flight": {
    "originLocationId": "string",
    "originCountryId": "string (optional)",
    "destinationLocationId": "string",
    "destinationCountryId": "string (optional)",
    "isInternational": "boolean",
    "departureDate": "string (ISO date)",
    "price": "number",
    "currency": "string",
    "cabinClass": "string (ECONOMY, PREMIUM_ECONOMY, BUSINESS, FIRST)",
    "stops": "number",
    "durationHours": "number (optional)"
  },
  "hotel": {
    "cityId": "string",
    "countryId": "string (optional)",
    "checkInDate": "string (ISO date)",
    "checkOutDate": "string (ISO date)",
    "pricePerNight": "number",
    "currency": "string",
    "starRating": "number (1-5)"
  }
}

Response:

{
  "bookingMode": "DIRECT_BOOKING | REQUEST_ONLY | HYBRID",
  "defaultAction": "ALLOW | WARN_AND_ALLOW | REQUIRE_APPROVAL | BLOCK",
  "flightEvaluation": {
    "compliant": "boolean",
    "action": "ALLOW | WARN_AND_ALLOW | REQUIRE_APPROVAL | BLOCK",
    "violations": [
      {
        "type": "PRICE | CABIN_CLASS | STOPS | ADVANCE_BOOKING",
        "message": "string",
        "limitValue": "number | string[]",
        "actualValue": "number | string",
        "excessAmount": "number (optional)"
      }
    ]
  },
  "matchedFlightRule": {
    "id": "string",
    "maxPricePerPerson": "number",
    "currency": "string",
    "allowedCabinClasses": "string[]",
    "maxStops": "number | null",
    "advanceBookingDays": "number | null",
    "originCityName": "string | null",
    "originCountryName": "string | null",
    "destinationCityName": "string | null",
    "destinationCountryName": "string | null",
    "isInternational": "boolean | null",
    "action": "ALLOW | WARN_AND_ALLOW | REQUIRE_APPROVAL | BLOCK | null"
  },
  "hotelEvaluation": {
    "compliant": "boolean",
    "action": "ALLOW | WARN_AND_ALLOW | REQUIRE_APPROVAL | BLOCK",
    "violations": [
      {
        "type": "PRICE | STAR_RATING | NIGHTS | ADVANCE_BOOKING",
        "message": "string",
        "limitValue": "number | string[]",
        "actualValue": "number | string",
        "excessAmount": "number (optional)"
      }
    ]
  },
  "matchedHotelRule": {
    "id": "string",
    "maxPricePerNight": "number",
    "currency": "string",
    "allowedStarRatings": "number[]",
    "maxNights": "number | null",
    "advanceBookingDays": "number | null",
    "cityName": "string | null",
    "countryName": "string | null",
    "action": "ALLOW | WARN_AND_ALLOW | REQUIRE_APPROVAL | BLOCK | null"
  }
}

List Policies

Get all policies for a company.

GET /api/v1/policies?companyId={companyId}

Query Parameters:

ParameterTypeDescription
companyIdstringFilter by company
isActivebooleanFilter by active status
isDefaultbooleanFilter by default status
pagenumberPage number (default: 1)
limitnumberItems per page (default: 20)

Response:

{
  "data": [
    {
      "id": "string",
      "name": "string",
      "description": "string | null",
      "companyId": "string",
      "bookingMode": "DIRECT_BOOKING | REQUEST_ONLY | HYBRID",
      "defaultAction": "ALLOW | WARN_AND_ALLOW | REQUIRE_APPROVAL | BLOCK",
      "isDefault": "boolean",
      "isActive": "boolean",
      "createdAt": "string (ISO date)",
      "updatedAt": "string (ISO date)"
    }
  ],
  "pagination": {
    "page": "number",
    "limit": "number",
    "total": "number",
    "totalPages": "number"
  }
}

Get Policy

Get a single policy with all rules.

GET /api/v1/policies/{policyId}

Response:

{
  "id": "string",
  "name": "string",
  "description": "string | null",
  "companyId": "string",
  "bookingMode": "DIRECT_BOOKING | REQUEST_ONLY | HYBRID",
  "defaultAction": "ALLOW | WARN_AND_ALLOW | REQUIRE_APPROVAL | BLOCK",
  "isDefault": "boolean",
  "isActive": "boolean",
  "flightRules": [
    {
      "id": "string",
      "priority": "number",
      "originCityId": "string | null",
      "originCountryId": "string | null",
      "destinationCityId": "string | null",
      "destinationCountryId": "string | null",
      "isInternational": "boolean | null",
      "maxPricePerPerson": "number | null",
      "currency": "string",
      "allowedCabinClasses": "string[]",
      "durationBudgetTiers": "DurationBudgetTier[] | null",
      "durationCabinTiers": "DurationCabinTier[] | null",
      "maxStops": "number | null",
      "advanceBookingDays": "number | null",
      "action": "ALLOW | WARN_AND_ALLOW | REQUIRE_APPROVAL | BLOCK | null"
    }
  ],
  "hotelRules": [
    {
      "id": "string",
      "priority": "number",
      "cityId": "string | null",
      "countryId": "string | null",
      "maxPricePerNight": "number | null",
      "currency": "string",
      "allowedStarRatings": "number[]",
      "maxNights": "number | null",
      "advanceBookingDays": "number | null",
      "action": "ALLOW | WARN_AND_ALLOW | REQUIRE_APPROVAL | BLOCK | null"
    }
  ],
  "createdAt": "string (ISO date)",
  "updatedAt": "string (ISO date)"
}

Create Policy

Create a new policy.

POST /api/v1/policies

Request Body:

{
  "name": "string (required, 2-200 chars)",
  "description": "string (optional)",
  "companyId": "string (required)",
  "bookingMode": "DIRECT_BOOKING | REQUEST_ONLY | HYBRID (required)",
  "defaultAction": "ALLOW | WARN_AND_ALLOW | REQUIRE_APPROVAL | BLOCK (required)",
  "isDefault": "boolean (optional, default: false)",
  "isActive": "boolean (optional, default: true)"
}

Update Policy

Update an existing policy.

PATCH /api/v1/policies/{policyId}

Request Body:

{
  "name": "string (optional)",
  "description": "string (optional)",
  "bookingMode": "DIRECT_BOOKING | REQUEST_ONLY | HYBRID (optional)",
  "defaultAction": "ALLOW | WARN_AND_ALLOW | REQUIRE_APPROVAL | BLOCK (optional)",
  "isDefault": "boolean (optional)",
  "isActive": "boolean (optional)"
}

Delete Policy

Soft-delete a policy.

DELETE /api/v1/policies/{policyId}

Cannot delete the company default policy. Set another policy as default first.

Flight Rule Endpoints

Create Flight Rule

POST /api/v1/policies/{policyId}/flight-rules

Update Flight Rule

PATCH /api/v1/policies/{policyId}/flight-rules/{ruleId}

Delete Flight Rule

DELETE /api/v1/policies/{policyId}/flight-rules/{ruleId}

Hotel Rule Endpoints

Create Hotel Rule

POST /api/v1/policies/{policyId}/hotel-rules

Update Hotel Rule

PATCH /api/v1/policies/{policyId}/hotel-rules/{ruleId}

Delete Hotel Rule

DELETE /api/v1/policies/{policyId}/hotel-rules/{ruleId}

Assignment Endpoints

Assign Policy to Role

POST /api/v1/policies/{policyId}/role-assignments

Request Body:

{
  "roleId": "string (required)"
}

Assign Policy to User

POST /api/v1/policies/{policyId}/user-assignments

Request Body:

{
  "userId": "string (required)",
  "effectiveFrom": "string (ISO date, optional)",
  "effectiveUntil": "string (ISO date, optional)"
}

Remove Role Assignment

DELETE /api/v1/policies/{policyId}/role-assignments/{roleId}

Remove User Assignment

DELETE /api/v1/policies/{policyId}/user-assignments/{userId}

Types

DurationBudgetTier

type DurationBudgetTier = {
  minHours: number;
  maxHours: number | null;
  maxPrice: number;
};

DurationCabinTier

type DurationCabinTier = {
  minHours: number;
  maxHours: number | null;
  classes: string[];
};

PolicyAction

type PolicyAction = 'ALLOW' | 'WARN_AND_ALLOW' | 'REQUIRE_APPROVAL' | 'BLOCK';

BookingMode

type BookingMode = 'DIRECT_BOOKING' | 'REQUEST_ONLY' | 'HYBRID';

ViolationType

type ViolationType = 
  | 'PRICE' 
  | 'CABIN_CLASS' 
  | 'STOPS' 
  | 'ADVANCE_BOOKING'
  | 'STAR_RATING'
  | 'NIGHTS';

Error Responses

400 Bad Request

{
  "statusCode": 400,
  "message": "Validation failed",
  "errors": [
    {
      "field": "name",
      "message": "Name must be between 2 and 200 characters"
    }
  ]
}

404 Not Found

{
  "statusCode": 404,
  "message": "Policy not found"
}

403 Forbidden

{
  "statusCode": 403,
  "message": "Cannot delete company default policy"
}

On this page