Skip to main content

Policies

A policy is the set of rules Nexa uses to decide which hotels are acceptable for a given case. Policies are versioned, activated explicitly, and matched to cases by context (airport / airline / country).

Why policies exist

Without policy, allocation has no opinion — it will happily book a 2-star motel for a Business-class passenger, or a 5-star inner-city property for an Economy group. Policies encode the operator's preferences, budget caps, quality standards, and special requirements outside the code, so they can evolve without a deploy.

Authoring a policy

curl -X POST https://us-central1.api.nexastudio.io/policies \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "MAD — VIP tiers",
"context": { "airport": "MAD", "airline": "XX" },
"tiers": ["BUSINESS", "FIRST", "CREW"],
"constraints": {
"minStars": 4,
"maxDistanceKm": 15,
"maxNightlyRate": 350,
"requiredAmenities": ["24H_RECEPTION", "AIRPORT_SHUTTLE"],
"excludedChains": ["BUDGETCHAIN"]
},
"buffers": {
"lateCheckoutMinutes": 120,
"earlyCheckInMinutes": 60
},
"mode": "ON_DEMAND",
"autoApproveDemand": false
}'

Activating and deactivating

A policy in DRAFT has no effect. Activate it with:

curl -X POST https://us-central1.api.nexastudio.io/policies/$POLICY_URN/activate

Activation freezes the previous version of the same context (same airport/airline/tier set) to ARCHIVED. To roll back, reactivate the archived version.

Matching rules

When a case needs allocation, Nexa looks for the most-specific active policy that matches:

  1. Exact airport + airline + tier.
  2. Then airport + tier.
  3. Then airline + tier.
  4. Then global by tier.

The first match wins. If no policy matches, the case lands in MANUAL_REVIEW with category POLICY_VIOLATION.

Constraint reference

ConstraintTypeNotes
minStars1–5Excludes unrated properties
maxDistanceKmnumberStraight-line from airport coordinates
maxNightlyRatenumber (currency)Currency is derived from policy context
requiredAmenitiesenum[]Normalized amenity tags
excludedChainsstring[]Provider-independent chain IDs
acceptedPaymentsenum[]Default: GUARANTEE; enable CARD for airports that require it
allowProvidersenum[]Restrict to a provider subset (e.g. contracts-only)

Operational flags

FlagEffect
mode: BATCHWaves run on a schedule to consolidate inventory queries
mode: ON_DEMANDWaves run the moment demand is approved
autoApproveDemandSkip the human checkpoint when roomsRequested ≤ maxAutomaticRoomsPerWave
incrementalRequiresApprovalForce manual approval on incremental requests even when auto-approve is on
consolidationWeight0.0–1.0 — how aggressively the scorer prefers fewer hotels

Natural-language synthesis

Operators can describe a policy in plain English and have Nexa generate the structured payload using the policy synthesizer — a Nexa Trained Model on Google:

curl -X POST https://us-central1.api.nexastudio.io/policies/synthesize \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"description": "For MAD business and first class, 4+ star only, within 15 km, must have 24-hour reception and airport shuttle. No budget chains."
}'

The response is a policy draft with provenance (source: "ai", confidence, prompt). A supervisor still has to review and activate.

See AI policy synthesis for prompt tuning and confidence thresholds.

Auditing policy changes

Every create / update / activate / deactivate writes an audit entry:

curl https://us-central1.api.nexastudio.io/audit?entity=policy&entityUrn=$POLICY_URN

You will see actor, timestamp, reason, and a before/after snapshot for every field that changed.

Common patterns

  • One policy per airport × tier is the most maintainable split. Avoid global policies.
  • Lower tiers need looser distance caps — Economy can accept 30 km, Business rarely accepts more than 15 km.
  • Keep excludedChains short. Prefer requiredAmenities and stars — they are easier to reason about and survive inventory churn.
  • Don't auto-approve incremental demand unless your airline has a trusted operations team upstream. Set incrementalRequiresApproval: true as a safe default.
Was this helpful?