Send a raw DMC itinerary as plain text. Get back a fully structured, day-by-day travel proposal — with narratives, activity details, hotel, meals, transfers, and destination photos — ready to render in your app.
One endpoint. Send your itinerary text, get a structured result. The call is synchronous — it holds the connection open and returns the full result when enrichment completes.
curl -X POST https://ai.supergryd.com/api/v1/enrich \
-H "Authorization: Bearer live_sg_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "Day 1: Arrive Ubud, check in to Alaya Resort. Spa treatment. Day 2: Tegalalang rice terrace, Tirta Empul temple...",
"customer_nights": 5,
"occasion": "Honeymoon",
"budget": "premium",
"pax_summary": "2 Adults"
}'All requests require a bearer token in the Authorization header.
Authorization: Bearer live_sg_YOUR_API_KEYKeep your key secret — it controls wallet spend. Contact your SuperGryd account manager to rotate or revoke.
Content-Type: application/json
| Field | Type | Description |
|---|---|---|
| text * | string | Raw DMC itinerary text. 100–50,000 characters. Plain text, HTML, or copy-pasted from a document. |
| customer_nights | number | Number of nights the customer is travelling. 1–90. Default: 1. Used to compress or extend the DMC itinerary to match the booking. |
| occasion | string | Trip purpose — shapes narrative tone. E.g. Honeymoon, Family Holiday, Adventure. Default: Leisure/Holiday. |
| budget | string | One of budget, comfort, premium. Influences activity and hotel narrative. Default: comfort. |
| pax_summary | string | Passenger description. E.g. 2 Adults, 1 Child (8). Used to generate relevant agent tips. Default: 2 Adults. |
| traveler_types | string[] | Optional traveler labels for personalised demographic tips. E.g. ["honeymooners","first-timers"]. |
| Header | Description |
|---|---|
| Idempotency-Key | Optional. A unique string per request. If a completed job with the same key exists (within 24 hours), the cached result is returned without a new enrichment call or wallet deduction. |
HTTP 200. The response envelope has two top-level fields:
{
"job_id": "93f465de-7844-4efd-aa96-49109990a3d4",
"result": {
"schema_version": "1.2",
"destination": "Tokyo & Kyoto & Osaka",
"duration_days": 8,
"pax_summary": "2 Adults",
"duration_action": "exact",
"inclusions": ["Daily breakfast", "Airport transfers"],
"exclusions": ["International flights", "Visa fees"],
"transfers": ["Private transfer: Narita → Hotel (Day 1)"],
"trip_maps_url": "https://www.google.com/maps/dir/Senso-ji+Temple+Tokyo/...",
"city_heroes": {
"tokyo": {
"url": "https://images.unsplash.com/...",
"photographer": "Louie Martinez",
"photographerUrl": "https://unsplash.com/@louie..."
}
},
"days": [ ... ]
}
}| Field | Type | Description |
|---|---|---|
| schema_version | string | Schema version of this response — e.g. 1.2. Use this to confirm which schema a response was generated against. Increments with every additive change. See the changelog for what changed per version. |
| destination | string | Primary destination label derived from the itinerary. |
| duration_days | number | Number of days (nights + 1) in the enriched itinerary. |
| pax_summary | string | Passenger description, echoed from the request or inferred. |
| duration_action | string | exact — DMC nights match. compress — DMC had more nights, merged to fit. extend — DMC had fewer nights, padded to fit. |
| inclusions | string[] | What's included in the package, extracted from the DMC text. |
| exclusions | string[] | What's not included, extracted from the DMC text. |
| transfers | string[] | Transfer descriptions extracted from the DMC text. |
| city_heroes | object | Map of lowercase city name → { url, photographer, photographerUrl }. Sourced from Unsplash via destination_images cache. Use as day banner images. May be empty if Unsplash lookup fails. |
| trip_maps_url | string | null | Google Maps directions URL covering all activity stops across every day of the trip. Null if fewer than 2 geocodable stops are found. Use this for a 'View full route on Google Maps' button. |
| days | M2Day[] | Ordered array of day objects. See below. |
| Field | Type | Description |
|---|---|---|
| day_number | number | 1-based day index. |
| day_title | string | Short descriptive title for the day. E.g. "Arrival & Bamboo Groves". |
| city | string | City or location for this day. |
| hotel | string | null | Hotel name extracted from DMC text, or null if not specified. |
| meals_included | string[] | Meals included from the hotel plan. E.g. ["Breakfast"]. |
| day_intro | string | null | Contextual intro sentence — arrival/departure/intercity travel context. Null for standard days. |
| hotel_confidence | string | Confidence level for the extracted hotel name: high, medium, or low. |
| day_metrics | M2DayMetrics | Fatigue and occasion scores for the day. See below. |
| day_maps_url | string | null | Google Maps directions URL for this day's activity stops only. Null if fewer than 1 geocodable stop is found. Use this for a 'View Day N on Google Maps' button. |
| slots | ItinerarySlot[] | Ordered activities, meals, and transfers for this day. |
| Field | Type | Description |
|---|---|---|
| fatigue_score | number | 1–10 score indicating physical intensity of the day's activities. |
| occasion_score | number | 1–10 score indicating how well the day suits the trip occasion (e.g. Honeymoon, Family). |
| Field | Type | Description |
|---|---|---|
| slot_index | number | 0-based position of this slot within the day. |
| slot_type | string | One of activity, meal, transfer, rest. |
| title | string | Short slot title. |
| narrative | string | 2–3 sentence description for activities, 1 sentence for meal/transfer slots. |
| time_hint | string | null | Loose time-of-day grouping: morning, afternoon, evening. Display hint only — not structural. |
| duration_mins | number | null | Estimated duration in minutes. Null if not determinable. |
| maps_link | string | null | Google Maps search URL. Format: https://www.google.com/maps/search/?api=1&query=PLACE+CITY. Present on activity and meal slots. |
| dining_link | string | null | Google Maps dining search URL. Present on meal slots only. |
| nearby_link | string | null | Google Maps "things to do" search URL for the day's city. |
| demographic_catering_note | string | null | Agent-facing tip tailored to the traveler profile (pax_summary / traveler_types). Shown as an amber tip box. |
| source | string | Origin of this slot: dmc = extracted directly from DMC text, ai_fill = AI-generated to fill the day, agent_custom = manually added by a SuperGryd agent. |
| is_mandatory | boolean | True if this slot has been locked by a SuperGryd agent and cannot be removed. |
| image_url | string | null | Auto-assigned Unsplash photo for this slot. Use this as the slot image when media[] is empty. |
| media | SlotMedia[] | Array of photos, YouTube videos, or links. Empty for freshly generated itineraries — API partners can populate this before rendering to add their own rich media. |
| Field | Type | Description |
|---|---|---|
| type | string | One of photo, youtube, link. |
| url | string | Photo: image URL. YouTube: bare video ID. Link: full URL. |
| thumbnail_url | string? | YouTube only: thumbnail URL. |
| title | string? | YouTube: video title. Link: page title. |
| alt | string? | Photo only: accessibility label for the image. |
| favicon_url | string? | Link only: favicon URL for the linked domain. |
| og_image | string? | Link only: og:image URL for a richer link preview. |
| description | string? | Link only: og:description or meta description of the linked page. |
All errors return { "error": { "code": "...", "message": "..." } } except auth errors which return { "error": "...", "message": "..." } (flat, no nesting).
| Code | HTTP | Description |
|---|---|---|
| missing_key | 401 | Authorization header missing or empty. |
| invalid_key | 401 | API key not found or invalid. |
| key_not_found | 401 | API key does not exist. |
| key_inactive | 403 | API key has been revoked. |
| invalid_body | 400 | Request body is not valid JSON. |
| input_too_short | 422 | text is under 100 characters. |
| input_too_long | 422 | text exceeds 50,000 characters. |
| invalid_nights | 422 | customer_nights is outside 1–90. |
| rejected_non_leisure | 422 | Input was rejected — not a leisure itinerary (e.g. MICE, flights-only). |
| parse_failed | 422 | Could not extract a structured itinerary from the text. |
| insufficient_balance | 402 | Wallet balance too low to process a call. |
| wallet_suspended | 403 | Wallet has been suspended. Contact your account manager. |
| no_wallet | 500 | Wallet record not found for this API key. Contact your account manager. |
| enrichment_failed | 500 | AI enrichment failed. Resubmit your request. |
| internal_error | 500 | Unexpected server error. |
The API uses a prepaid wallet. Each enrichment call deducts from your wallet at submission. Calls rejected before reaching enrichment — auth errors, validation errors, insufficient balance — are not charged.
Check your usage at any time:
curl https://ai.supergryd.com/api/v1/keys \
-H "Authorization: Bearer live_sg_YOUR_KEY"To top up your wallet or discuss pricing, contact your SuperGryd account manager.
See what the output looks like
Three rendered examples — Bali, Maldives, Japan — using real API responses.
Schema stability
The API is v1. Changes within v1 are additive only. Build your parser to ignore unknown fields. Breaking changes increment to v2 with advance notice.