repull 0.2.0 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/repull/api/ai_api.rb +1 -1
- data/lib/repull/api/airbnb_api.rb +271 -16
- data/lib/repull/api/atlas_api.rb +1 -1
- data/lib/repull/api/availability_api.rb +1 -1
- data/lib/repull/api/billing_api.rb +1 -1
- data/lib/repull/api/booking_com_api.rb +133 -1
- data/lib/repull/api/connect_api.rb +3 -3
- data/lib/repull/api/conversations_api.rb +27 -5
- data/lib/repull/api/guests_api.rb +14 -3
- data/lib/repull/api/kv_api.rb +361 -0
- data/lib/repull/api/listings_api.rb +26 -9
- data/lib/repull/api/markets_api.rb +14 -3
- data/lib/repull/api/plumguide_api.rb +1 -1
- data/lib/repull/api/pricing_api.rb +14 -3
- data/lib/repull/api/properties_api.rb +32 -8
- data/lib/repull/api/reservations_api.rb +34 -5
- data/lib/repull/api/reviews_api.rb +14 -3
- data/lib/repull/api/schema_api.rb +1 -1
- data/lib/repull/api/studio_api.rb +1094 -0
- data/lib/repull/api/system_api.rb +1 -1
- data/lib/repull/api/vrbo_api.rb +31 -3
- data/lib/repull/api/webhooks_api.rb +16 -5
- data/lib/repull/api_client.rb +1 -1
- data/lib/repull/api_error.rb +1 -1
- data/lib/repull/api_model_base.rb +1 -1
- data/lib/repull/configuration.rb +1 -1
- data/lib/repull/models/account_created_event.rb +217 -0
- data/lib/repull/models/account_created_payload.rb +185 -0
- data/lib/repull/models/account_disconnected_event.rb +217 -0
- data/lib/repull/models/account_disconnected_payload.rb +196 -0
- data/lib/repull/models/ai_operation.rb +1 -1
- data/lib/repull/models/ai_operation_completed_event.rb +217 -0
- data/lib/repull/models/ai_operation_completed_payload.rb +197 -0
- data/lib/repull/models/ai_operation_failed_event.rb +217 -0
- data/lib/repull/models/ai_operation_failed_payload.rb +175 -0
- data/lib/repull/models/ai_operation_failed_payload_error.rb +156 -0
- data/lib/repull/models/airbnb_connection.rb +242 -0
- data/lib/repull/models/airbnb_connection_accessibility_amenities_inner.rb +167 -0
- data/lib/repull/models/airbnb_connection_amenities_inner.rb +168 -0
- data/lib/repull/models/airbnb_connection_host.rb +244 -0
- data/lib/repull/models/airbnb_connection_response.rb +164 -0
- data/lib/repull/models/airbnb_connection_summary.rb +231 -0
- data/lib/repull/models/airbnb_data_freshness.rb +201 -0
- data/lib/repull/models/airbnb_listing.rb +25 -74
- data/lib/repull/models/airbnb_listing_list_response.rb +65 -5
- data/lib/repull/models/airbnb_reservation.rb +1 -1
- data/lib/repull/models/airbnb_reservation_list_response.rb +2 -1
- data/lib/repull/models/airbnb_review.rb +1 -1
- data/lib/repull/models/airbnb_review_list_response.rb +1 -1
- data/lib/repull/models/airbnb_thread.rb +1 -1
- data/lib/repull/models/airbnb_thread_list_response.rb +1 -1
- data/lib/repull/models/booking_connect_listing_option.rb +1 -1
- data/lib/repull/models/booking_connect_room.rb +1 -1
- data/lib/repull/models/booking_connect_rooms_response.rb +1 -1
- data/lib/repull/models/booking_conversation.rb +1 -1
- data/lib/repull/models/booking_conversation_list_response.rb +1 -1
- data/lib/repull/models/booking_pricing_rate_update.rb +1 -1
- data/lib/repull/models/booking_pricing_rate_update_date_range.rb +1 -1
- data/lib/repull/models/booking_pricing_rate_update_restrictions.rb +1 -1
- data/lib/repull/models/booking_pricing_response.rb +1 -1
- data/lib/repull/models/booking_pricing_update_request.rb +1 -1
- data/lib/repull/models/booking_pricing_update_response.rb +1 -1
- data/lib/repull/models/booking_property.rb +1 -1
- data/lib/repull/models/booking_property_list_response.rb +1 -1
- data/lib/repull/models/booking_room_mapping.rb +1 -1
- data/lib/repull/models/booking_verify_hotel_request.rb +1 -1
- data/lib/repull/models/booking_verify_hotel_response.rb +1 -1
- data/lib/repull/models/bulk_pricing_failure.rb +1 -1
- data/lib/repull/models/bulk_pricing_item.rb +1 -1
- data/lib/repull/models/bulk_pricing_request.rb +1 -1
- data/lib/repull/models/bulk_pricing_response.rb +1 -1
- data/lib/repull/models/calendar_day.rb +1 -1
- data/lib/repull/models/calendar_response.rb +1 -1
- data/lib/repull/models/calendar_updated_event.rb +217 -0
- data/lib/repull/models/calendar_updated_payload.rb +184 -0
- data/lib/repull/models/calendar_updated_payload_range.rb +156 -0
- data/lib/repull/models/clear_kv200_response.rb +147 -0
- data/lib/repull/models/connect_host.rb +1 -1
- data/lib/repull/models/connect_provider.rb +1 -1
- data/lib/repull/models/connect_provider_list_response.rb +1 -1
- data/lib/repull/models/connect_session.rb +1 -1
- data/lib/repull/models/connect_status.rb +1 -1
- data/lib/repull/models/connection.rb +1 -1
- data/lib/repull/models/connection_list_response.rb +1 -1
- data/lib/repull/models/conversation.rb +1 -1
- data/lib/repull/models/conversation_detail.rb +1 -1
- data/lib/repull/models/conversation_guest.rb +1 -1
- data/lib/repull/models/conversation_guest_contact.rb +1 -1
- data/lib/repull/models/conversation_host.rb +1 -1
- data/lib/repull/models/conversation_list_response.rb +1 -1
- data/lib/repull/models/conversation_message_attachment.rb +1 -1
- data/lib/repull/models/create_ai_operation200_response.rb +1 -1
- data/lib/repull/models/create_billing_checkout_request.rb +1 -1
- data/lib/repull/models/create_connect_session_request.rb +1 -1
- data/lib/repull/models/create_connection_request.rb +1 -1
- data/lib/repull/models/create_reservation_request.rb +1 -1
- data/lib/repull/models/create_studio_deployment201_response.rb +147 -0
- data/lib/repull/models/create_studio_deployment201_response_data.rb +199 -0
- data/lib/repull/models/create_studio_deployment_request.rb +165 -0
- data/lib/repull/models/create_studio_project201_response.rb +147 -0
- data/lib/repull/models/create_studio_project201_response_data.rb +199 -0
- data/lib/repull/models/create_studio_project_generation201_response.rb +147 -0
- data/lib/repull/models/create_studio_project_generation201_response_data.rb +165 -0
- data/lib/repull/models/create_studio_project_generation_request.rb +165 -0
- data/lib/repull/models/create_studio_project_request.rb +203 -0
- data/lib/repull/models/create_webhook_request.rb +2 -2
- data/lib/repull/models/custom_schema.rb +1 -1
- data/lib/repull/models/custom_schema_create.rb +1 -1
- data/lib/repull/models/custom_schema_create_response.rb +1 -1
- data/lib/repull/models/custom_schema_delete_response.rb +1 -1
- data/lib/repull/models/custom_schema_list_response.rb +1 -1
- data/lib/repull/models/custom_schema_summary.rb +1 -1
- data/lib/repull/models/custom_schema_update.rb +1 -1
- data/lib/repull/models/delete_kv200_response.rb +147 -0
- data/lib/repull/models/delete_studio_deployment200_response.rb +147 -0
- data/lib/repull/models/delete_studio_deployment200_response_data.rb +156 -0
- data/lib/repull/models/delete_studio_project200_response.rb +147 -0
- data/lib/repull/models/delete_studio_project200_response_data.rb +156 -0
- data/lib/repull/models/delete_studio_project_file200_response.rb +147 -0
- data/lib/repull/models/delete_studio_project_file200_response_data.rb +156 -0
- data/lib/repull/models/error.rb +1 -1
- data/lib/repull/models/error_error.rb +1 -1
- data/lib/repull/models/error_error_support.rb +1 -1
- data/lib/repull/models/generate_studio_completion200_response.rb +147 -0
- data/lib/repull/models/generate_studio_completion200_response_data.rb +224 -0
- data/lib/repull/models/generate_studio_completion_request.rb +305 -0
- data/lib/repull/models/generate_studio_completion_request_project_id.rb +105 -0
- data/lib/repull/models/get_health200_response.rb +1 -1
- data/lib/repull/models/get_studio_deployment200_response.rb +147 -0
- data/lib/repull/models/get_studio_project200_response.rb +147 -0
- data/lib/repull/models/guest.rb +1 -1
- data/lib/repull/models/guest_contact.rb +1 -1
- data/lib/repull/models/guest_flag.rb +1 -1
- data/lib/repull/models/guest_list_response.rb +1 -1
- data/lib/repull/models/guest_note.rb +1 -1
- data/lib/repull/models/guest_profile.rb +1 -1
- data/lib/repull/models/guest_reservations_summary.rb +1 -1
- data/lib/repull/models/list_kv200_response.rb +158 -0
- data/lib/repull/models/list_kv200_response_data_inner.rb +176 -0
- data/lib/repull/models/list_kv200_response_pagination.rb +156 -0
- data/lib/repull/models/list_studio_deployments200_response.rb +158 -0
- data/lib/repull/models/list_studio_project_files200_response.rb +149 -0
- data/lib/repull/models/list_studio_projects200_response.rb +149 -0
- data/lib/repull/models/listing.rb +36 -2
- data/lib/repull/models/listing_address.rb +1 -1
- data/lib/repull/models/listing_amenity.rb +215 -0
- data/lib/repull/models/listing_channel.rb +1 -1
- data/lib/repull/models/listing_comp.rb +1 -1
- data/lib/repull/models/listing_comp_nightly.rb +1 -1
- data/lib/repull/models/listing_comp_ratings.rb +1 -1
- data/lib/repull/models/listing_comps_response.rb +1 -1
- data/lib/repull/models/listing_content.rb +54 -13
- data/lib/repull/models/listing_create_request.rb +1 -1
- data/lib/repull/models/listing_create_response.rb +1 -1
- data/lib/repull/models/listing_created_event.rb +217 -0
- data/lib/repull/models/listing_created_payload.rb +202 -0
- data/lib/repull/models/listing_created_payload_address.rb +165 -0
- data/lib/repull/models/listing_deleted_event.rb +217 -0
- data/lib/repull/models/listing_deleted_payload.rb +167 -0
- data/lib/repull/models/listing_details.rb +374 -0
- data/lib/repull/models/listing_generate_content_request.rb +2 -2
- data/lib/repull/models/listing_generate_content_response.rb +1 -1
- data/lib/repull/models/listing_list_response.rb +1 -1
- data/lib/repull/models/listing_pricing_apply_request.rb +1 -1
- data/lib/repull/models/listing_pricing_apply_response.rb +1 -1
- data/lib/repull/models/listing_pricing_history_entry.rb +1 -1
- data/lib/repull/models/listing_pricing_history_response.rb +1 -1
- data/lib/repull/models/listing_pricing_recommendation.rb +1 -1
- data/lib/repull/models/listing_pricing_response.rb +1 -1
- data/lib/repull/models/listing_pricing_response_comp_summary.rb +1 -1
- data/lib/repull/models/listing_pricing_response_date_range.rb +1 -1
- data/lib/repull/models/listing_pricing_response_listing.rb +1 -1
- data/lib/repull/models/listing_pricing_strategy.rb +1 -1
- data/lib/repull/models/listing_pricing_strategy_input.rb +1 -1
- data/lib/repull/models/listing_publish_airbnb_request.rb +1 -1
- data/lib/repull/models/listing_publish_response.rb +1 -1
- data/lib/repull/models/listing_publish_status_channel.rb +1 -1
- data/lib/repull/models/listing_publish_status_connection.rb +180 -0
- data/lib/repull/models/listing_publish_status_response.rb +18 -5
- data/lib/repull/models/listing_quality_tier.rb +1 -1
- data/lib/repull/models/listing_segment.rb +1 -1
- data/lib/repull/models/listing_segment_recommendation.rb +1 -1
- data/lib/repull/models/listing_segments_response.rb +1 -1
- data/lib/repull/models/listing_segments_response_scope.rb +1 -1
- data/lib/repull/models/listing_updated_event.rb +217 -0
- data/lib/repull/models/listing_updated_payload.rb +169 -0
- data/lib/repull/models/map_connect_booking_rooms_request.rb +1 -1
- data/lib/repull/models/map_connect_booking_rooms_response.rb +1 -1
- data/lib/repull/models/market_browse_category.rb +1 -1
- data/lib/repull/models/market_browse_entry.rb +1 -1
- data/lib/repull/models/market_browse_featured.rb +1 -1
- data/lib/repull/models/market_browse_response.rb +1 -1
- data/lib/repull/models/market_calendar_day.rb +1 -1
- data/lib/repull/models/market_calendar_day_events_inner.rb +1 -1
- data/lib/repull/models/market_calendar_response.rb +1 -1
- data/lib/repull/models/market_detail_response.rb +1 -1
- data/lib/repull/models/market_detail_response_price_distribution_inner.rb +1 -1
- data/lib/repull/models/market_detail_response_property_type_mix_inner.rb +1 -1
- data/lib/repull/models/market_detail_response_supply_trend_inner.rb +1 -1
- data/lib/repull/models/market_detail_response_top_comps.rb +1 -1
- data/lib/repull/models/market_event.rb +1 -1
- data/lib/repull/models/market_my_listing.rb +1 -1
- data/lib/repull/models/market_summary.rb +1 -1
- data/lib/repull/models/market_top_comp.rb +1 -1
- data/lib/repull/models/markets_overview_response.rb +2 -2
- data/lib/repull/models/markets_overview_response_browse.rb +1 -1
- data/lib/repull/models/markets_overview_response_subscriptions.rb +1 -1
- data/lib/repull/models/markets_overview_response_totals.rb +1 -1
- data/lib/repull/models/message.rb +1 -1
- data/lib/repull/models/message_list_response.rb +1 -1
- data/lib/repull/models/pagination.rb +1 -1
- data/lib/repull/models/payment_completed_event.rb +217 -0
- data/lib/repull/models/payment_completed_payload.rb +193 -0
- data/lib/repull/models/payment_refunded_event.rb +217 -0
- data/lib/repull/models/payment_refunded_payload.rb +193 -0
- data/lib/repull/models/plumguide_listing.rb +1 -1
- data/lib/repull/models/plumguide_listing_list_response.rb +1 -1
- data/lib/repull/models/property.rb +17 -5
- data/lib/repull/models/property_list_response.rb +1 -1
- data/lib/repull/models/reply_booking_review200_response.rb +147 -0
- data/lib/repull/models/reply_booking_review_request.rb +219 -0
- data/lib/repull/models/repull_ping_event.rb +217 -0
- data/lib/repull/models/repull_ping_payload.rb +148 -0
- data/lib/repull/models/reservation.rb +74 -89
- data/lib/repull/models/reservation_cancelled_event.rb +217 -0
- data/lib/repull/models/reservation_cancelled_payload.rb +196 -0
- data/lib/repull/models/reservation_created_event.rb +218 -0
- data/lib/repull/models/reservation_created_payload.rb +165 -0
- data/lib/repull/models/reservation_financials.rb +172 -0
- data/lib/repull/models/reservation_list_response.rb +1 -1
- data/lib/repull/models/reservation_message_received_event.rb +217 -0
- data/lib/repull/models/reservation_message_received_payload.rb +184 -0
- data/lib/repull/models/reservation_message_received_payload_from.rb +157 -0
- data/lib/repull/models/reservation_occupancy.rb +190 -0
- data/lib/repull/models/reservation_primary_guest.rb +202 -0
- data/lib/repull/models/reservation_updated_event.rb +217 -0
- data/lib/repull/models/reservation_updated_payload.rb +177 -0
- data/lib/repull/models/reservation_webhook_object.rb +355 -0
- data/lib/repull/models/respond_airbnb_review_request.rb +174 -0
- data/lib/repull/models/review.rb +1 -1
- data/lib/repull/models/review_category.rb +1 -1
- data/lib/repull/models/review_list_response.rb +1 -1
- data/lib/repull/models/review_response.rb +1 -1
- data/lib/repull/models/rotate_webhook_secret200_response.rb +1 -1
- data/lib/repull/models/select_connect_provider_request.rb +1 -1
- data/lib/repull/models/select_provider_response.rb +1 -1
- data/lib/repull/models/set_kv_request.rb +180 -0
- data/lib/repull/models/studio_deployment.rb +207 -0
- data/lib/repull/models/studio_error.rb +148 -0
- data/lib/repull/models/studio_error_error.rb +212 -0
- data/lib/repull/models/studio_file.rb +188 -0
- data/lib/repull/models/studio_generation.rb +215 -0
- data/lib/repull/models/studio_project.rb +241 -0
- data/lib/repull/models/test_webhook_request.rb +24 -2
- data/lib/repull/models/update_availability_request.rb +1 -1
- data/lib/repull/models/update_listing_pricing_strategy200_response.rb +1 -1
- data/lib/repull/models/update_reservation_request.rb +1 -1
- data/lib/repull/models/update_studio_project_request.rb +190 -0
- data/lib/repull/models/update_webhook_request.rb +2 -2
- data/lib/repull/models/upsert_studio_project_file200_response.rb +147 -0
- data/lib/repull/models/upsert_studio_project_file200_response_data.rb +147 -0
- data/lib/repull/models/upsert_studio_project_file_request.rb +165 -0
- data/lib/repull/models/vrbo_listing.rb +1 -1
- data/lib/repull/models/vrbo_listing_list_response.rb +1 -1
- data/lib/repull/models/vrbo_reservation.rb +1 -1
- data/lib/repull/models/vrbo_reservation_list_response.rb +1 -1
- data/lib/repull/models/webhook_delivery.rb +25 -2
- data/lib/repull/models/webhook_delivery_detail.rb +26 -3
- data/lib/repull/models/webhook_delivery_list_response.rb +1 -1
- data/lib/repull/models/webhook_event.rb +82 -0
- data/lib/repull/models/webhook_event_catalog.rb +18 -5
- data/lib/repull/models/webhook_event_catalog_domains_inner.rb +2 -2
- data/lib/repull/models/{webhook_event_catalog_domains_inner_events_inner.rb → webhook_event_catalog_entry.rb} +28 -5
- data/lib/repull/models/webhook_event_type.rb +53 -0
- data/lib/repull/models/webhook_list_response.rb +1 -1
- data/lib/repull/models/webhook_subscription.rb +2 -2
- data/lib/repull/version.rb +2 -2
- data/lib/repull.rb +97 -2
- data/openapi/v1.json +8717 -4724
- data/scripts/regen.sh +1 -1
- metadata +99 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a46040a8387e0532bc035b3f4886095e1ba0a30b75faf8588f6c554fb578ff85
|
|
4
|
+
data.tar.gz: 3388c282a6de9d52377a8e9531cd3746f9f77f83a77a7b777f172e6031d77b8b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f2714192b3afb49b4307efed60968690c22b24eaff18790f768ed3e1ea14a70672059c8c1096f453bf84e00e4e17bf84f3fcfafb5d3966b0e8af2ff442bf16f7
|
|
7
|
+
data.tar.gz: d4df0f4caada56de2d3ac5751d8d228917ad8fc7e95c8931e6bf23e4c5d3a02156396b41c18c8c294e80b11b286981445f0f3487f87f5d6b8285d58c06925686
|
data/lib/repull/api/ai_api.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
=begin
|
|
2
2
|
#Repull API
|
|
3
3
|
|
|
4
|
-
#The unified API for vacation rental tech. Connect to 50+ PMS platforms and 4 OTA channels through one REST API. Built-in AI operations for guest communication, pricing, and listing optimization. ## Designed for AI agents Every error response on this API includes machine-parseable fields so an LLM (Claude in MCP, Cursor, Cline, GPT, etc.) can self-recover without escalating to a human: - `error.code` — stable string identifier (e.g. `invalid_params`, `rate_limit_exceeded`) - `error.message` — human-readable cause - `error.fix` — exact recovery steps (e.g. \"Pass `check_in_after` as ISO 8601: `?check_in_after=2026-01-15`\") - `error.docs_url` — link to the canonical write-up at `https://repull.dev/docs/errors/{code}` - `error.request_id` — id to correlate with server-side logs - `error.field` / `error.value_received` / `error.valid_values` / `error.did_you_mean` — when the error is parameter-specific - `error.retry_after` — seconds to wait before retrying (rate-limit + transient upstream) `Access-Control-Expose-Headers` lists `x-request-id` and the `X-RateLimit-*` family so browsers can read them on cross-origin responses. ## Quick Start 1. Get an API key at https://repull.dev/dashboard 2. Connect a PMS: `POST /v1/connect/{provider}` 3. List properties: `GET /v1/properties` 4. Get reservations: `GET /v1/reservations` ## Authentication All requests require a Bearer token: ``` Authorization: Bearer sk_test_YOUR_API_KEY ``` Sandbox keys start with `sk_test_`, production with `sk_live_`. ## Request Correlation (X-Request-ID) Every response carries an `X-Request-ID` header, e.g. `X-Request-ID: req_01HXY...`. Include this id in support tickets and bug reports — we can trace the full request lifecycle (auth, rate limit, handler, downstream calls, log row) from a single id. You may set the header on the inbound request to forward your own trace id; we will echo it back instead of generating a new one. Accepted format: `^[\\\\w.-]{1,128}$`. The id is also embedded in error envelopes as `request_id` so server-side log diffs work even when the response headers are stripped by an intermediate proxy. ## Rate Limits The public API enforces a per-API-key sliding-window rate limit on top of the per-tier monthly + daily-AI quotas. **Default policy:** 600 requests per 60 seconds, per API key. Sliding window — there is no fixed-minute boundary you can burst across. Every response includes: | Header | Meaning | |---|---| | `X-RateLimit-Limit` | Requests permitted in the current window. | | `X-RateLimit-Remaining` | Requests left in the current window after this call. | | `X-RateLimit-Reset` | Unix epoch (seconds) when the next slot opens. | | `X-RateLimit-Policy` | Machine-readable policy descriptor, e.g. `600;w=60`. | | `Retry-After` | Seconds to wait before retrying. **Only present on 429 responses.** | **On 429 (rate_limit_exceeded):** the response body matches the standard error envelope with `code: \"rate_limit_exceeded\"`, plus `limit`, `window_seconds`, `retry_after`, and `request_id` fields. SDKs MUST honor `Retry-After` and use exponential backoff with jitter on subsequent retries — never a tight loop. Recommended backoff: ``` sleep_ms = (Retry-After * 1000) + random(0..250) ``` Monthly + daily-AI tier quotas (`free`, `starter`, `
|
|
4
|
+
#The unified API for vacation rental tech. Connect to 50+ PMS platforms and 4 OTA channels through one REST API. Built-in AI operations for guest communication, pricing, and listing optimization. ## Designed for AI agents Every error response on this API includes machine-parseable fields so an LLM (Claude in MCP, Cursor, Cline, GPT, etc.) can self-recover without escalating to a human: - `error.code` — stable string identifier (e.g. `invalid_params`, `rate_limit_exceeded`) - `error.message` — human-readable cause - `error.fix` — exact recovery steps (e.g. \"Pass `check_in_after` as ISO 8601: `?check_in_after=2026-01-15`\") - `error.docs_url` — link to the canonical write-up at `https://repull.dev/docs/errors/{code}` - `error.request_id` — id to correlate with server-side logs - `error.field` / `error.value_received` / `error.valid_values` / `error.did_you_mean` — when the error is parameter-specific - `error.retry_after` — seconds to wait before retrying (rate-limit + transient upstream) `Access-Control-Expose-Headers` lists `x-request-id` and the `X-RateLimit-*` family so browsers can read them on cross-origin responses. ## Quick Start 1. Get an API key at https://repull.dev/dashboard 2. Connect a PMS: `POST /v1/connect/{provider}` 3. List properties: `GET /v1/properties` 4. Get reservations: `GET /v1/reservations` ## Authentication All requests require a Bearer token: ``` Authorization: Bearer sk_test_YOUR_API_KEY ``` Sandbox keys start with `sk_test_`, production with `sk_live_`. ## Request Correlation (X-Request-ID) Every response carries an `X-Request-ID` header, e.g. `X-Request-ID: req_01HXY...`. Include this id in support tickets and bug reports — we can trace the full request lifecycle (auth, rate limit, handler, downstream calls, log row) from a single id. You may set the header on the inbound request to forward your own trace id; we will echo it back instead of generating a new one. Accepted format: `^[\\\\w.-]{1,128}$`. The id is also embedded in error envelopes as `request_id` so server-side log diffs work even when the response headers are stripped by an intermediate proxy. ## Rate Limits The public API enforces a per-API-key sliding-window rate limit on top of the per-tier monthly + daily-AI quotas. **Default policy:** 600 requests per 60 seconds, per API key. Sliding window — there is no fixed-minute boundary you can burst across. Every response includes: | Header | Meaning | |---|---| | `X-RateLimit-Limit` | Requests permitted in the current window. | | `X-RateLimit-Remaining` | Requests left in the current window after this call. | | `X-RateLimit-Reset` | Unix epoch (seconds) when the next slot opens. | | `X-RateLimit-Policy` | Machine-readable policy descriptor, e.g. `600;w=60`. | | `Retry-After` | Seconds to wait before retrying. **Only present on 429 responses.** | **On 429 (rate_limit_exceeded):** the response body matches the standard error envelope with `code: \"rate_limit_exceeded\"`, plus `limit`, `window_seconds`, `retry_after`, and `request_id` fields. SDKs MUST honor `Retry-After` and use exponential backoff with jitter on subsequent retries — never a tight loop. Recommended backoff: ``` sleep_ms = (Retry-After * 1000) + random(0..250) ``` Monthly + daily-AI tier quotas (`free`, `starter`, `custom`) are enforced separately and also surface as 429s; they include `tier`, `scope`, and `resets_at` fields.
|
|
5
5
|
|
|
6
6
|
The version of the OpenAPI document: 1.0.0
|
|
7
7
|
Contact: ivan@vanio.ai
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
=begin
|
|
2
2
|
#Repull API
|
|
3
3
|
|
|
4
|
-
#The unified API for vacation rental tech. Connect to 50+ PMS platforms and 4 OTA channels through one REST API. Built-in AI operations for guest communication, pricing, and listing optimization. ## Designed for AI agents Every error response on this API includes machine-parseable fields so an LLM (Claude in MCP, Cursor, Cline, GPT, etc.) can self-recover without escalating to a human: - `error.code` — stable string identifier (e.g. `invalid_params`, `rate_limit_exceeded`) - `error.message` — human-readable cause - `error.fix` — exact recovery steps (e.g. \"Pass `check_in_after` as ISO 8601: `?check_in_after=2026-01-15`\") - `error.docs_url` — link to the canonical write-up at `https://repull.dev/docs/errors/{code}` - `error.request_id` — id to correlate with server-side logs - `error.field` / `error.value_received` / `error.valid_values` / `error.did_you_mean` — when the error is parameter-specific - `error.retry_after` — seconds to wait before retrying (rate-limit + transient upstream) `Access-Control-Expose-Headers` lists `x-request-id` and the `X-RateLimit-*` family so browsers can read them on cross-origin responses. ## Quick Start 1. Get an API key at https://repull.dev/dashboard 2. Connect a PMS: `POST /v1/connect/{provider}` 3. List properties: `GET /v1/properties` 4. Get reservations: `GET /v1/reservations` ## Authentication All requests require a Bearer token: ``` Authorization: Bearer sk_test_YOUR_API_KEY ``` Sandbox keys start with `sk_test_`, production with `sk_live_`. ## Request Correlation (X-Request-ID) Every response carries an `X-Request-ID` header, e.g. `X-Request-ID: req_01HXY...`. Include this id in support tickets and bug reports — we can trace the full request lifecycle (auth, rate limit, handler, downstream calls, log row) from a single id. You may set the header on the inbound request to forward your own trace id; we will echo it back instead of generating a new one. Accepted format: `^[\\\\w.-]{1,128}$`. The id is also embedded in error envelopes as `request_id` so server-side log diffs work even when the response headers are stripped by an intermediate proxy. ## Rate Limits The public API enforces a per-API-key sliding-window rate limit on top of the per-tier monthly + daily-AI quotas. **Default policy:** 600 requests per 60 seconds, per API key. Sliding window — there is no fixed-minute boundary you can burst across. Every response includes: | Header | Meaning | |---|---| | `X-RateLimit-Limit` | Requests permitted in the current window. | | `X-RateLimit-Remaining` | Requests left in the current window after this call. | | `X-RateLimit-Reset` | Unix epoch (seconds) when the next slot opens. | | `X-RateLimit-Policy` | Machine-readable policy descriptor, e.g. `600;w=60`. | | `Retry-After` | Seconds to wait before retrying. **Only present on 429 responses.** | **On 429 (rate_limit_exceeded):** the response body matches the standard error envelope with `code: \"rate_limit_exceeded\"`, plus `limit`, `window_seconds`, `retry_after`, and `request_id` fields. SDKs MUST honor `Retry-After` and use exponential backoff with jitter on subsequent retries — never a tight loop. Recommended backoff: ``` sleep_ms = (Retry-After * 1000) + random(0..250) ``` Monthly + daily-AI tier quotas (`free`, `starter`, `
|
|
4
|
+
#The unified API for vacation rental tech. Connect to 50+ PMS platforms and 4 OTA channels through one REST API. Built-in AI operations for guest communication, pricing, and listing optimization. ## Designed for AI agents Every error response on this API includes machine-parseable fields so an LLM (Claude in MCP, Cursor, Cline, GPT, etc.) can self-recover without escalating to a human: - `error.code` — stable string identifier (e.g. `invalid_params`, `rate_limit_exceeded`) - `error.message` — human-readable cause - `error.fix` — exact recovery steps (e.g. \"Pass `check_in_after` as ISO 8601: `?check_in_after=2026-01-15`\") - `error.docs_url` — link to the canonical write-up at `https://repull.dev/docs/errors/{code}` - `error.request_id` — id to correlate with server-side logs - `error.field` / `error.value_received` / `error.valid_values` / `error.did_you_mean` — when the error is parameter-specific - `error.retry_after` — seconds to wait before retrying (rate-limit + transient upstream) `Access-Control-Expose-Headers` lists `x-request-id` and the `X-RateLimit-*` family so browsers can read them on cross-origin responses. ## Quick Start 1. Get an API key at https://repull.dev/dashboard 2. Connect a PMS: `POST /v1/connect/{provider}` 3. List properties: `GET /v1/properties` 4. Get reservations: `GET /v1/reservations` ## Authentication All requests require a Bearer token: ``` Authorization: Bearer sk_test_YOUR_API_KEY ``` Sandbox keys start with `sk_test_`, production with `sk_live_`. ## Request Correlation (X-Request-ID) Every response carries an `X-Request-ID` header, e.g. `X-Request-ID: req_01HXY...`. Include this id in support tickets and bug reports — we can trace the full request lifecycle (auth, rate limit, handler, downstream calls, log row) from a single id. You may set the header on the inbound request to forward your own trace id; we will echo it back instead of generating a new one. Accepted format: `^[\\\\w.-]{1,128}$`. The id is also embedded in error envelopes as `request_id` so server-side log diffs work even when the response headers are stripped by an intermediate proxy. ## Rate Limits The public API enforces a per-API-key sliding-window rate limit on top of the per-tier monthly + daily-AI quotas. **Default policy:** 600 requests per 60 seconds, per API key. Sliding window — there is no fixed-minute boundary you can burst across. Every response includes: | Header | Meaning | |---|---| | `X-RateLimit-Limit` | Requests permitted in the current window. | | `X-RateLimit-Remaining` | Requests left in the current window after this call. | | `X-RateLimit-Reset` | Unix epoch (seconds) when the next slot opens. | | `X-RateLimit-Policy` | Machine-readable policy descriptor, e.g. `600;w=60`. | | `Retry-After` | Seconds to wait before retrying. **Only present on 429 responses.** | **On 429 (rate_limit_exceeded):** the response body matches the standard error envelope with `code: \"rate_limit_exceeded\"`, plus `limit`, `window_seconds`, `retry_after`, and `request_id` fields. SDKs MUST honor `Retry-After` and use exponential backoff with jitter on subsequent retries — never a tight loop. Recommended backoff: ``` sleep_ms = (Retry-After * 1000) + random(0..250) ``` Monthly + daily-AI tier quotas (`free`, `starter`, `custom`) are enforced separately and also surface as 429s; they include `tier`, `scope`, and `resets_at` fields.
|
|
5
5
|
|
|
6
6
|
The version of the OpenAPI document: 1.0.0
|
|
7
7
|
Contact: ivan@vanio.ai
|
|
@@ -198,10 +198,142 @@ module Repull
|
|
|
198
198
|
return data, status_code, headers
|
|
199
199
|
end
|
|
200
200
|
|
|
201
|
+
# Edit Airbnb host review
|
|
202
|
+
# Edit a host-side review for an Airbnb stay. Airbnb collapses POST + PUT into the same upstream call (`PUT /v2/listing_reviews/{id}`), so this endpoint covers both initial submit and subsequent edits while the review window is open. Body is a partial `AirbnbReview` — pass the fields you want to change (rating, public review, private feedback, category ratings).
|
|
203
|
+
# @param id [String] Airbnb review id (`HRabc123` style).
|
|
204
|
+
# @param airbnb_review [AirbnbReview]
|
|
205
|
+
# @param [Hash] opts the optional parameters
|
|
206
|
+
# @return [AirbnbReview]
|
|
207
|
+
def edit_airbnb_review(id, airbnb_review, opts = {})
|
|
208
|
+
data, _status_code, _headers = edit_airbnb_review_with_http_info(id, airbnb_review, opts)
|
|
209
|
+
data
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# Edit Airbnb host review
|
|
213
|
+
# Edit a host-side review for an Airbnb stay. Airbnb collapses POST + PUT into the same upstream call (`PUT /v2/listing_reviews/{id}`), so this endpoint covers both initial submit and subsequent edits while the review window is open. Body is a partial `AirbnbReview` — pass the fields you want to change (rating, public review, private feedback, category ratings).
|
|
214
|
+
# @param id [String] Airbnb review id (`HRabc123` style).
|
|
215
|
+
# @param airbnb_review [AirbnbReview]
|
|
216
|
+
# @param [Hash] opts the optional parameters
|
|
217
|
+
# @return [Array<(AirbnbReview, Integer, Hash)>] AirbnbReview data, response status code and response headers
|
|
218
|
+
def edit_airbnb_review_with_http_info(id, airbnb_review, opts = {})
|
|
219
|
+
if @api_client.config.debugging
|
|
220
|
+
@api_client.config.logger.debug 'Calling API: AirbnbApi.edit_airbnb_review ...'
|
|
221
|
+
end
|
|
222
|
+
# verify the required parameter 'id' is set
|
|
223
|
+
if @api_client.config.client_side_validation && id.nil?
|
|
224
|
+
fail ArgumentError, "Missing the required parameter 'id' when calling AirbnbApi.edit_airbnb_review"
|
|
225
|
+
end
|
|
226
|
+
# verify the required parameter 'airbnb_review' is set
|
|
227
|
+
if @api_client.config.client_side_validation && airbnb_review.nil?
|
|
228
|
+
fail ArgumentError, "Missing the required parameter 'airbnb_review' when calling AirbnbApi.edit_airbnb_review"
|
|
229
|
+
end
|
|
230
|
+
# resource path
|
|
231
|
+
local_var_path = '/v1/channels/airbnb/reviews/{id}'.sub('{id}', CGI.escape(id.to_s))
|
|
232
|
+
|
|
233
|
+
# query parameters
|
|
234
|
+
query_params = opts[:query_params] || {}
|
|
235
|
+
|
|
236
|
+
# header parameters
|
|
237
|
+
header_params = opts[:header_params] || {}
|
|
238
|
+
# HTTP header 'Accept' (if needed)
|
|
239
|
+
header_params['Accept'] = @api_client.select_header_accept(['application/json']) unless header_params['Accept']
|
|
240
|
+
# HTTP header 'Content-Type'
|
|
241
|
+
content_type = @api_client.select_header_content_type(['application/json'])
|
|
242
|
+
if !content_type.nil?
|
|
243
|
+
header_params['Content-Type'] = content_type
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
# form parameters
|
|
247
|
+
form_params = opts[:form_params] || {}
|
|
248
|
+
|
|
249
|
+
# http body (model)
|
|
250
|
+
post_body = opts[:debug_body] || @api_client.object_to_http_body(airbnb_review)
|
|
251
|
+
|
|
252
|
+
# return_type
|
|
253
|
+
return_type = opts[:debug_return_type] || 'AirbnbReview'
|
|
254
|
+
|
|
255
|
+
# auth_names
|
|
256
|
+
auth_names = opts[:debug_auth_names] || ['bearerAuth']
|
|
257
|
+
|
|
258
|
+
new_options = opts.merge(
|
|
259
|
+
:operation => :"AirbnbApi.edit_airbnb_review",
|
|
260
|
+
:header_params => header_params,
|
|
261
|
+
:query_params => query_params,
|
|
262
|
+
:form_params => form_params,
|
|
263
|
+
:body => post_body,
|
|
264
|
+
:auth_names => auth_names,
|
|
265
|
+
:return_type => return_type
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
data, status_code, headers = @api_client.call_api(:PUT, local_var_path, new_options)
|
|
269
|
+
if @api_client.config.debugging
|
|
270
|
+
@api_client.config.logger.debug "API called: AirbnbApi#edit_airbnb_review\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
|
|
271
|
+
end
|
|
272
|
+
return data, status_code, headers
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
# Get Airbnb connection state
|
|
276
|
+
# Returns the workspace's Airbnb host connection state in one envelope. Use this instead of inferring connection health from per-listing 401s on `GET /v1/channels/airbnb/listings` — that's noisy (every per-listing call has to fail before you know) and ambiguous (a single 5xx looks identical to a deauth). Pure DB read — does NOT touch Airbnb's API, so it's cheap to poll from a status-page surface. The response includes one row per Airbnb host the workspace has linked. Each row carries `isConnected`, `lastSyncedAt`, `deactivatedAt`, and `lastDisconnectReason` (most recent non-backfill row in `airbnb_host_events`). A self-serve `fixUrl` is included whenever `status` is anything other than `connected` — points at the dashboard where the host re-authorizes (or initiates the first OAuth flow for `never_connected` workspaces).
|
|
277
|
+
# @param [Hash] opts the optional parameters
|
|
278
|
+
# @return [AirbnbConnectionResponse]
|
|
279
|
+
def get_airbnb_connection(opts = {})
|
|
280
|
+
data, _status_code, _headers = get_airbnb_connection_with_http_info(opts)
|
|
281
|
+
data
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# Get Airbnb connection state
|
|
285
|
+
# Returns the workspace's Airbnb host connection state in one envelope. Use this instead of inferring connection health from per-listing 401s on `GET /v1/channels/airbnb/listings` — that's noisy (every per-listing call has to fail before you know) and ambiguous (a single 5xx looks identical to a deauth). Pure DB read — does NOT touch Airbnb's API, so it's cheap to poll from a status-page surface. The response includes one row per Airbnb host the workspace has linked. Each row carries `isConnected`, `lastSyncedAt`, `deactivatedAt`, and `lastDisconnectReason` (most recent non-backfill row in `airbnb_host_events`). A self-serve `fixUrl` is included whenever `status` is anything other than `connected` — points at the dashboard where the host re-authorizes (or initiates the first OAuth flow for `never_connected` workspaces).
|
|
286
|
+
# @param [Hash] opts the optional parameters
|
|
287
|
+
# @return [Array<(AirbnbConnectionResponse, Integer, Hash)>] AirbnbConnectionResponse data, response status code and response headers
|
|
288
|
+
def get_airbnb_connection_with_http_info(opts = {})
|
|
289
|
+
if @api_client.config.debugging
|
|
290
|
+
@api_client.config.logger.debug 'Calling API: AirbnbApi.get_airbnb_connection ...'
|
|
291
|
+
end
|
|
292
|
+
# resource path
|
|
293
|
+
local_var_path = '/v1/channels/airbnb/connection'
|
|
294
|
+
|
|
295
|
+
# query parameters
|
|
296
|
+
query_params = opts[:query_params] || {}
|
|
297
|
+
|
|
298
|
+
# header parameters
|
|
299
|
+
header_params = opts[:header_params] || {}
|
|
300
|
+
# HTTP header 'Accept' (if needed)
|
|
301
|
+
header_params['Accept'] = @api_client.select_header_accept(['application/json']) unless header_params['Accept']
|
|
302
|
+
|
|
303
|
+
# form parameters
|
|
304
|
+
form_params = opts[:form_params] || {}
|
|
305
|
+
|
|
306
|
+
# http body (model)
|
|
307
|
+
post_body = opts[:debug_body]
|
|
308
|
+
|
|
309
|
+
# return_type
|
|
310
|
+
return_type = opts[:debug_return_type] || 'AirbnbConnectionResponse'
|
|
311
|
+
|
|
312
|
+
# auth_names
|
|
313
|
+
auth_names = opts[:debug_auth_names] || ['bearerAuth']
|
|
314
|
+
|
|
315
|
+
new_options = opts.merge(
|
|
316
|
+
:operation => :"AirbnbApi.get_airbnb_connection",
|
|
317
|
+
:header_params => header_params,
|
|
318
|
+
:query_params => query_params,
|
|
319
|
+
:form_params => form_params,
|
|
320
|
+
:body => post_body,
|
|
321
|
+
:auth_names => auth_names,
|
|
322
|
+
:return_type => return_type
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
data, status_code, headers = @api_client.call_api(:GET, local_var_path, new_options)
|
|
326
|
+
if @api_client.config.debugging
|
|
327
|
+
@api_client.config.logger.debug "API called: AirbnbApi#get_airbnb_connection\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
|
|
328
|
+
end
|
|
329
|
+
return data, status_code, headers
|
|
330
|
+
end
|
|
331
|
+
|
|
201
332
|
# Get Airbnb listing
|
|
202
|
-
# Fetch a single
|
|
333
|
+
# Fetch all Airbnb connection rows for a single Vanio listing id. A property may be linked from multiple Airbnb hosts — every match is returned. Pass `?include=amenities` to enrich each row with its current Airbnb amenities.
|
|
203
334
|
# @param id [String]
|
|
204
335
|
# @param [Hash] opts the optional parameters
|
|
336
|
+
# @option opts [String] :include Comma-separated expansions. Currently supported: `amenities`.
|
|
205
337
|
# @return [AirbnbListing]
|
|
206
338
|
def get_airbnb_listing(id, opts = {})
|
|
207
339
|
data, _status_code, _headers = get_airbnb_listing_with_http_info(id, opts)
|
|
@@ -209,9 +341,10 @@ module Repull
|
|
|
209
341
|
end
|
|
210
342
|
|
|
211
343
|
# Get Airbnb listing
|
|
212
|
-
# Fetch a single
|
|
344
|
+
# Fetch all Airbnb connection rows for a single Vanio listing id. A property may be linked from multiple Airbnb hosts — every match is returned. Pass `?include=amenities` to enrich each row with its current Airbnb amenities.
|
|
213
345
|
# @param id [String]
|
|
214
346
|
# @param [Hash] opts the optional parameters
|
|
347
|
+
# @option opts [String] :include Comma-separated expansions. Currently supported: `amenities`.
|
|
215
348
|
# @return [Array<(AirbnbListing, Integer, Hash)>] AirbnbListing data, response status code and response headers
|
|
216
349
|
def get_airbnb_listing_with_http_info(id, opts = {})
|
|
217
350
|
if @api_client.config.debugging
|
|
@@ -226,6 +359,7 @@ module Repull
|
|
|
226
359
|
|
|
227
360
|
# query parameters
|
|
228
361
|
query_params = opts[:query_params] || {}
|
|
362
|
+
query_params[:'include'] = opts[:'include'] if !opts[:'include'].nil?
|
|
229
363
|
|
|
230
364
|
# header parameters
|
|
231
365
|
header_params = opts[:header_params] || {}
|
|
@@ -508,8 +642,9 @@ module Repull
|
|
|
508
642
|
end
|
|
509
643
|
|
|
510
644
|
# List Airbnb listings
|
|
511
|
-
# List every Airbnb listing this workspace has access to via the connected Airbnb account.
|
|
645
|
+
# List every Airbnb listing this workspace has access to via the connected Airbnb account. **Pure DB read — never calls Airbnb upstream.** The connect flow is what populates the local cache; the API serves what's already there. Customers with a disconnected host still see their last-synced data, with the top-level `data_freshness` envelope flagging the staleness and pointing at the reconnect URL. Pass `?include=amenities` to enrich each connection with its locally-cached amenity set. Returns `null` per connection when the cache is empty.
|
|
512
646
|
# @param [Hash] opts the optional parameters
|
|
647
|
+
# @option opts [String] :include Comma-separated expansions. Currently supported: `amenities` (adds `amenities` and `accessibility_amenities` arrays to each connection, sourced from the local `listings_airbnb_amenities` cache).
|
|
513
648
|
# @return [AirbnbListingListResponse]
|
|
514
649
|
def list_airbnb_listings(opts = {})
|
|
515
650
|
data, _status_code, _headers = list_airbnb_listings_with_http_info(opts)
|
|
@@ -517,8 +652,9 @@ module Repull
|
|
|
517
652
|
end
|
|
518
653
|
|
|
519
654
|
# List Airbnb listings
|
|
520
|
-
# List every Airbnb listing this workspace has access to via the connected Airbnb account.
|
|
655
|
+
# List every Airbnb listing this workspace has access to via the connected Airbnb account. **Pure DB read — never calls Airbnb upstream.** The connect flow is what populates the local cache; the API serves what's already there. Customers with a disconnected host still see their last-synced data, with the top-level `data_freshness` envelope flagging the staleness and pointing at the reconnect URL. Pass `?include=amenities` to enrich each connection with its locally-cached amenity set. Returns `null` per connection when the cache is empty.
|
|
521
656
|
# @param [Hash] opts the optional parameters
|
|
657
|
+
# @option opts [String] :include Comma-separated expansions. Currently supported: `amenities` (adds `amenities` and `accessibility_amenities` arrays to each connection, sourced from the local `listings_airbnb_amenities` cache).
|
|
522
658
|
# @return [Array<(AirbnbListingListResponse, Integer, Hash)>] AirbnbListingListResponse data, response status code and response headers
|
|
523
659
|
def list_airbnb_listings_with_http_info(opts = {})
|
|
524
660
|
if @api_client.config.debugging
|
|
@@ -529,6 +665,7 @@ module Repull
|
|
|
529
665
|
|
|
530
666
|
# query parameters
|
|
531
667
|
query_params = opts[:query_params] || {}
|
|
668
|
+
query_params[:'include'] = opts[:'include'] if !opts[:'include'].nil?
|
|
532
669
|
|
|
533
670
|
# header parameters
|
|
534
671
|
header_params = opts[:header_params] || {}
|
|
@@ -565,8 +702,16 @@ module Repull
|
|
|
565
702
|
end
|
|
566
703
|
|
|
567
704
|
# List Airbnb reservations
|
|
568
|
-
#
|
|
705
|
+
# Cursor-paginated list of reservations sourced directly from Airbnb. Use this when you need Airbnb-specific fields (guest payout split, cancellation policy snapshot) that the unified `/v1/reservations` endpoint flattens away. Walk pages with `?cursor=<pagination.next_cursor>` until `pagination.has_more` is `false`. The cursor is opaque — never construct or parse it client-side. `?offset=` is also accepted as a first-class alias for shallow paging (0..10000) — see the `offset` parameter below. Mutually exclusive with `cursor`. Internally this walks upstream Airbnb cursor pages to skip rows, so deep offsets cost N/limit upstream round-trips; cursor remains the better choice for deep pagination. When `status` is omitted, all statuses are returned (Airbnb defaults to `accepted` only on its own surface, but this endpoint normalises to \"all\"). Pass `?status=accepted` to scope.
|
|
569
706
|
# @param [Hash] opts the optional parameters
|
|
707
|
+
# @option opts [String] :cursor Opaque cursor returned by the previous response's `pagination.next_cursor`. Omit to fetch the first page.
|
|
708
|
+
# @option opts [Integer] :offset First-class alias for cursor-based pagination. Mutually exclusive with `cursor` — passing both returns 422. Accepts integers in `[0, 10000]`; deeper walks must use `cursor` (constant per-page cost). The response always includes `pagination.next_cursor` so consumers can switch from offset → cursor mid-walk for deep pagination without re-keying. (default to 0)
|
|
709
|
+
# @option opts [Integer] :limit Max items per page. Hard cap is 100. (default to 50)
|
|
710
|
+
# @option opts [String] :listing_id Filter to one Airbnb listing id (numeric string).
|
|
711
|
+
# @option opts [String] :status Filter by reservation status. Omit to receive all statuses.
|
|
712
|
+
# @option opts [Date] :start_date ISO 8601 (YYYY-MM-DD) lower bound on Airbnb's date range filter.
|
|
713
|
+
# @option opts [Date] :end_date ISO 8601 (YYYY-MM-DD) upper bound on Airbnb's date range filter.
|
|
714
|
+
# @option opts [Boolean] :include_total Whether to include `pagination.total`. Always populated when Airbnb returns a total count (effectively always); accepted for shape symmetry with the rest of the API. (default to true)
|
|
570
715
|
# @return [AirbnbReservationListResponse]
|
|
571
716
|
def list_airbnb_reservations(opts = {})
|
|
572
717
|
data, _status_code, _headers = list_airbnb_reservations_with_http_info(opts)
|
|
@@ -574,18 +719,54 @@ module Repull
|
|
|
574
719
|
end
|
|
575
720
|
|
|
576
721
|
# List Airbnb reservations
|
|
577
|
-
#
|
|
722
|
+
# Cursor-paginated list of reservations sourced directly from Airbnb. Use this when you need Airbnb-specific fields (guest payout split, cancellation policy snapshot) that the unified `/v1/reservations` endpoint flattens away. Walk pages with `?cursor=<pagination.next_cursor>` until `pagination.has_more` is `false`. The cursor is opaque — never construct or parse it client-side. `?offset=` is also accepted as a first-class alias for shallow paging (0..10000) — see the `offset` parameter below. Mutually exclusive with `cursor`. Internally this walks upstream Airbnb cursor pages to skip rows, so deep offsets cost N/limit upstream round-trips; cursor remains the better choice for deep pagination. When `status` is omitted, all statuses are returned (Airbnb defaults to `accepted` only on its own surface, but this endpoint normalises to \"all\"). Pass `?status=accepted` to scope.
|
|
578
723
|
# @param [Hash] opts the optional parameters
|
|
724
|
+
# @option opts [String] :cursor Opaque cursor returned by the previous response's `pagination.next_cursor`. Omit to fetch the first page.
|
|
725
|
+
# @option opts [Integer] :offset First-class alias for cursor-based pagination. Mutually exclusive with `cursor` — passing both returns 422. Accepts integers in `[0, 10000]`; deeper walks must use `cursor` (constant per-page cost). The response always includes `pagination.next_cursor` so consumers can switch from offset → cursor mid-walk for deep pagination without re-keying. (default to 0)
|
|
726
|
+
# @option opts [Integer] :limit Max items per page. Hard cap is 100. (default to 50)
|
|
727
|
+
# @option opts [String] :listing_id Filter to one Airbnb listing id (numeric string).
|
|
728
|
+
# @option opts [String] :status Filter by reservation status. Omit to receive all statuses.
|
|
729
|
+
# @option opts [Date] :start_date ISO 8601 (YYYY-MM-DD) lower bound on Airbnb's date range filter.
|
|
730
|
+
# @option opts [Date] :end_date ISO 8601 (YYYY-MM-DD) upper bound on Airbnb's date range filter.
|
|
731
|
+
# @option opts [Boolean] :include_total Whether to include `pagination.total`. Always populated when Airbnb returns a total count (effectively always); accepted for shape symmetry with the rest of the API. (default to true)
|
|
579
732
|
# @return [Array<(AirbnbReservationListResponse, Integer, Hash)>] AirbnbReservationListResponse data, response status code and response headers
|
|
580
733
|
def list_airbnb_reservations_with_http_info(opts = {})
|
|
581
734
|
if @api_client.config.debugging
|
|
582
735
|
@api_client.config.logger.debug 'Calling API: AirbnbApi.list_airbnb_reservations ...'
|
|
583
736
|
end
|
|
737
|
+
if @api_client.config.client_side_validation && !opts[:'offset'].nil? && opts[:'offset'] > 10000
|
|
738
|
+
fail ArgumentError, 'invalid value for "opts[:"offset"]" when calling AirbnbApi.list_airbnb_reservations, must be smaller than or equal to 10000.'
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
if @api_client.config.client_side_validation && !opts[:'offset'].nil? && opts[:'offset'] < 0
|
|
742
|
+
fail ArgumentError, 'invalid value for "opts[:"offset"]" when calling AirbnbApi.list_airbnb_reservations, must be greater than or equal to 0.'
|
|
743
|
+
end
|
|
744
|
+
|
|
745
|
+
if @api_client.config.client_side_validation && !opts[:'limit'].nil? && opts[:'limit'] > 100
|
|
746
|
+
fail ArgumentError, 'invalid value for "opts[:"limit"]" when calling AirbnbApi.list_airbnb_reservations, must be smaller than or equal to 100.'
|
|
747
|
+
end
|
|
748
|
+
|
|
749
|
+
if @api_client.config.client_side_validation && !opts[:'limit'].nil? && opts[:'limit'] < 1
|
|
750
|
+
fail ArgumentError, 'invalid value for "opts[:"limit"]" when calling AirbnbApi.list_airbnb_reservations, must be greater than or equal to 1.'
|
|
751
|
+
end
|
|
752
|
+
|
|
753
|
+
allowable_values = ["pending", "accepted", "denied", "cancelled", "completed", "failed_verification", "request_voided"]
|
|
754
|
+
if @api_client.config.client_side_validation && opts[:'status'] && !allowable_values.include?(opts[:'status'])
|
|
755
|
+
fail ArgumentError, "invalid value for \"status\", must be one of #{allowable_values}"
|
|
756
|
+
end
|
|
584
757
|
# resource path
|
|
585
758
|
local_var_path = '/v1/channels/airbnb/reservations'
|
|
586
759
|
|
|
587
760
|
# query parameters
|
|
588
761
|
query_params = opts[:query_params] || {}
|
|
762
|
+
query_params[:'cursor'] = opts[:'cursor'] if !opts[:'cursor'].nil?
|
|
763
|
+
query_params[:'offset'] = opts[:'offset'] if !opts[:'offset'].nil?
|
|
764
|
+
query_params[:'limit'] = opts[:'limit'] if !opts[:'limit'].nil?
|
|
765
|
+
query_params[:'listing_id'] = opts[:'listing_id'] if !opts[:'listing_id'].nil?
|
|
766
|
+
query_params[:'status'] = opts[:'status'] if !opts[:'status'].nil?
|
|
767
|
+
query_params[:'start_date'] = opts[:'start_date'] if !opts[:'start_date'].nil?
|
|
768
|
+
query_params[:'end_date'] = opts[:'end_date'] if !opts[:'end_date'].nil?
|
|
769
|
+
query_params[:'include_total'] = opts[:'include_total'] if !opts[:'include_total'].nil?
|
|
589
770
|
|
|
590
771
|
# header parameters
|
|
591
772
|
header_params = opts[:header_params] || {}
|
|
@@ -799,21 +980,95 @@ module Repull
|
|
|
799
980
|
end
|
|
800
981
|
|
|
801
982
|
# Respond to Airbnb review
|
|
802
|
-
# Post a public response to a guest review. Airbnb allows one response per review — repeated POSTs return 409.
|
|
983
|
+
# Post a public host response to a guest review. Airbnb allows one response per review — repeated POSTs return 409. Response text is capped at 1000 characters.
|
|
984
|
+
# @param id [String] Airbnb review id.
|
|
985
|
+
# @param respond_airbnb_review_request [RespondAirbnbReviewRequest]
|
|
986
|
+
# @param [Hash] opts the optional parameters
|
|
987
|
+
# @return [AirbnbReview]
|
|
988
|
+
def respond_airbnb_review(id, respond_airbnb_review_request, opts = {})
|
|
989
|
+
data, _status_code, _headers = respond_airbnb_review_with_http_info(id, respond_airbnb_review_request, opts)
|
|
990
|
+
data
|
|
991
|
+
end
|
|
992
|
+
|
|
993
|
+
# Respond to Airbnb review
|
|
994
|
+
# Post a public host response to a guest review. Airbnb allows one response per review — repeated POSTs return 409. Response text is capped at 1000 characters.
|
|
995
|
+
# @param id [String] Airbnb review id.
|
|
996
|
+
# @param respond_airbnb_review_request [RespondAirbnbReviewRequest]
|
|
997
|
+
# @param [Hash] opts the optional parameters
|
|
998
|
+
# @return [Array<(AirbnbReview, Integer, Hash)>] AirbnbReview data, response status code and response headers
|
|
999
|
+
def respond_airbnb_review_with_http_info(id, respond_airbnb_review_request, opts = {})
|
|
1000
|
+
if @api_client.config.debugging
|
|
1001
|
+
@api_client.config.logger.debug 'Calling API: AirbnbApi.respond_airbnb_review ...'
|
|
1002
|
+
end
|
|
1003
|
+
# verify the required parameter 'id' is set
|
|
1004
|
+
if @api_client.config.client_side_validation && id.nil?
|
|
1005
|
+
fail ArgumentError, "Missing the required parameter 'id' when calling AirbnbApi.respond_airbnb_review"
|
|
1006
|
+
end
|
|
1007
|
+
# verify the required parameter 'respond_airbnb_review_request' is set
|
|
1008
|
+
if @api_client.config.client_side_validation && respond_airbnb_review_request.nil?
|
|
1009
|
+
fail ArgumentError, "Missing the required parameter 'respond_airbnb_review_request' when calling AirbnbApi.respond_airbnb_review"
|
|
1010
|
+
end
|
|
1011
|
+
# resource path
|
|
1012
|
+
local_var_path = '/v1/channels/airbnb/reviews/{id}/respond'.sub('{id}', CGI.escape(id.to_s))
|
|
1013
|
+
|
|
1014
|
+
# query parameters
|
|
1015
|
+
query_params = opts[:query_params] || {}
|
|
1016
|
+
|
|
1017
|
+
# header parameters
|
|
1018
|
+
header_params = opts[:header_params] || {}
|
|
1019
|
+
# HTTP header 'Accept' (if needed)
|
|
1020
|
+
header_params['Accept'] = @api_client.select_header_accept(['application/json']) unless header_params['Accept']
|
|
1021
|
+
# HTTP header 'Content-Type'
|
|
1022
|
+
content_type = @api_client.select_header_content_type(['application/json'])
|
|
1023
|
+
if !content_type.nil?
|
|
1024
|
+
header_params['Content-Type'] = content_type
|
|
1025
|
+
end
|
|
1026
|
+
|
|
1027
|
+
# form parameters
|
|
1028
|
+
form_params = opts[:form_params] || {}
|
|
1029
|
+
|
|
1030
|
+
# http body (model)
|
|
1031
|
+
post_body = opts[:debug_body] || @api_client.object_to_http_body(respond_airbnb_review_request)
|
|
1032
|
+
|
|
1033
|
+
# return_type
|
|
1034
|
+
return_type = opts[:debug_return_type] || 'AirbnbReview'
|
|
1035
|
+
|
|
1036
|
+
# auth_names
|
|
1037
|
+
auth_names = opts[:debug_auth_names] || ['bearerAuth']
|
|
1038
|
+
|
|
1039
|
+
new_options = opts.merge(
|
|
1040
|
+
:operation => :"AirbnbApi.respond_airbnb_review",
|
|
1041
|
+
:header_params => header_params,
|
|
1042
|
+
:query_params => query_params,
|
|
1043
|
+
:form_params => form_params,
|
|
1044
|
+
:body => post_body,
|
|
1045
|
+
:auth_names => auth_names,
|
|
1046
|
+
:return_type => return_type
|
|
1047
|
+
)
|
|
1048
|
+
|
|
1049
|
+
data, status_code, headers = @api_client.call_api(:POST, local_var_path, new_options)
|
|
1050
|
+
if @api_client.config.debugging
|
|
1051
|
+
@api_client.config.logger.debug "API called: AirbnbApi#respond_airbnb_review\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
|
|
1052
|
+
end
|
|
1053
|
+
return data, status_code, headers
|
|
1054
|
+
end
|
|
1055
|
+
|
|
1056
|
+
# Respond to / submit Airbnb review (legacy)
|
|
1057
|
+
# Legacy action-based shape. Body `{ action: \"respond\"|\"submit\", reviewId, response?, review? }`. Kept for backwards compatibility — prefer `PUT /v1/channels/airbnb/reviews/{id}` (edit) and `POST /v1/channels/airbnb/reviews/{id}/respond` (reply) for new integrations.
|
|
803
1058
|
# @param [Hash] opts the optional parameters
|
|
804
1059
|
# @return [nil]
|
|
805
|
-
def
|
|
806
|
-
|
|
1060
|
+
def respond_airbnb_review_legacy(opts = {})
|
|
1061
|
+
respond_airbnb_review_legacy_with_http_info(opts)
|
|
807
1062
|
nil
|
|
808
1063
|
end
|
|
809
1064
|
|
|
810
|
-
# Respond to Airbnb review
|
|
811
|
-
#
|
|
1065
|
+
# Respond to / submit Airbnb review (legacy)
|
|
1066
|
+
# Legacy action-based shape. Body `{ action: \"respond\"|\"submit\", reviewId, response?, review? }`. Kept for backwards compatibility — prefer `PUT /v1/channels/airbnb/reviews/{id}` (edit) and `POST /v1/channels/airbnb/reviews/{id}/respond` (reply) for new integrations.
|
|
812
1067
|
# @param [Hash] opts the optional parameters
|
|
813
1068
|
# @return [Array<(nil, Integer, Hash)>] nil, response status code and response headers
|
|
814
|
-
def
|
|
1069
|
+
def respond_airbnb_review_legacy_with_http_info(opts = {})
|
|
815
1070
|
if @api_client.config.debugging
|
|
816
|
-
@api_client.config.logger.debug 'Calling API: AirbnbApi.
|
|
1071
|
+
@api_client.config.logger.debug 'Calling API: AirbnbApi.respond_airbnb_review_legacy ...'
|
|
817
1072
|
end
|
|
818
1073
|
# resource path
|
|
819
1074
|
local_var_path = '/v1/channels/airbnb/reviews'
|
|
@@ -837,7 +1092,7 @@ module Repull
|
|
|
837
1092
|
auth_names = opts[:debug_auth_names] || ['bearerAuth']
|
|
838
1093
|
|
|
839
1094
|
new_options = opts.merge(
|
|
840
|
-
:operation => :"AirbnbApi.
|
|
1095
|
+
:operation => :"AirbnbApi.respond_airbnb_review_legacy",
|
|
841
1096
|
:header_params => header_params,
|
|
842
1097
|
:query_params => query_params,
|
|
843
1098
|
:form_params => form_params,
|
|
@@ -848,7 +1103,7 @@ module Repull
|
|
|
848
1103
|
|
|
849
1104
|
data, status_code, headers = @api_client.call_api(:POST, local_var_path, new_options)
|
|
850
1105
|
if @api_client.config.debugging
|
|
851
|
-
@api_client.config.logger.debug "API called: AirbnbApi#
|
|
1106
|
+
@api_client.config.logger.debug "API called: AirbnbApi#respond_airbnb_review_legacy\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
|
|
852
1107
|
end
|
|
853
1108
|
return data, status_code, headers
|
|
854
1109
|
end
|
data/lib/repull/api/atlas_api.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
=begin
|
|
2
2
|
#Repull API
|
|
3
3
|
|
|
4
|
-
#The unified API for vacation rental tech. Connect to 50+ PMS platforms and 4 OTA channels through one REST API. Built-in AI operations for guest communication, pricing, and listing optimization. ## Designed for AI agents Every error response on this API includes machine-parseable fields so an LLM (Claude in MCP, Cursor, Cline, GPT, etc.) can self-recover without escalating to a human: - `error.code` — stable string identifier (e.g. `invalid_params`, `rate_limit_exceeded`) - `error.message` — human-readable cause - `error.fix` — exact recovery steps (e.g. \"Pass `check_in_after` as ISO 8601: `?check_in_after=2026-01-15`\") - `error.docs_url` — link to the canonical write-up at `https://repull.dev/docs/errors/{code}` - `error.request_id` — id to correlate with server-side logs - `error.field` / `error.value_received` / `error.valid_values` / `error.did_you_mean` — when the error is parameter-specific - `error.retry_after` — seconds to wait before retrying (rate-limit + transient upstream) `Access-Control-Expose-Headers` lists `x-request-id` and the `X-RateLimit-*` family so browsers can read them on cross-origin responses. ## Quick Start 1. Get an API key at https://repull.dev/dashboard 2. Connect a PMS: `POST /v1/connect/{provider}` 3. List properties: `GET /v1/properties` 4. Get reservations: `GET /v1/reservations` ## Authentication All requests require a Bearer token: ``` Authorization: Bearer sk_test_YOUR_API_KEY ``` Sandbox keys start with `sk_test_`, production with `sk_live_`. ## Request Correlation (X-Request-ID) Every response carries an `X-Request-ID` header, e.g. `X-Request-ID: req_01HXY...`. Include this id in support tickets and bug reports — we can trace the full request lifecycle (auth, rate limit, handler, downstream calls, log row) from a single id. You may set the header on the inbound request to forward your own trace id; we will echo it back instead of generating a new one. Accepted format: `^[\\\\w.-]{1,128}$`. The id is also embedded in error envelopes as `request_id` so server-side log diffs work even when the response headers are stripped by an intermediate proxy. ## Rate Limits The public API enforces a per-API-key sliding-window rate limit on top of the per-tier monthly + daily-AI quotas. **Default policy:** 600 requests per 60 seconds, per API key. Sliding window — there is no fixed-minute boundary you can burst across. Every response includes: | Header | Meaning | |---|---| | `X-RateLimit-Limit` | Requests permitted in the current window. | | `X-RateLimit-Remaining` | Requests left in the current window after this call. | | `X-RateLimit-Reset` | Unix epoch (seconds) when the next slot opens. | | `X-RateLimit-Policy` | Machine-readable policy descriptor, e.g. `600;w=60`. | | `Retry-After` | Seconds to wait before retrying. **Only present on 429 responses.** | **On 429 (rate_limit_exceeded):** the response body matches the standard error envelope with `code: \"rate_limit_exceeded\"`, plus `limit`, `window_seconds`, `retry_after`, and `request_id` fields. SDKs MUST honor `Retry-After` and use exponential backoff with jitter on subsequent retries — never a tight loop. Recommended backoff: ``` sleep_ms = (Retry-After * 1000) + random(0..250) ``` Monthly + daily-AI tier quotas (`free`, `starter`, `
|
|
4
|
+
#The unified API for vacation rental tech. Connect to 50+ PMS platforms and 4 OTA channels through one REST API. Built-in AI operations for guest communication, pricing, and listing optimization. ## Designed for AI agents Every error response on this API includes machine-parseable fields so an LLM (Claude in MCP, Cursor, Cline, GPT, etc.) can self-recover without escalating to a human: - `error.code` — stable string identifier (e.g. `invalid_params`, `rate_limit_exceeded`) - `error.message` — human-readable cause - `error.fix` — exact recovery steps (e.g. \"Pass `check_in_after` as ISO 8601: `?check_in_after=2026-01-15`\") - `error.docs_url` — link to the canonical write-up at `https://repull.dev/docs/errors/{code}` - `error.request_id` — id to correlate with server-side logs - `error.field` / `error.value_received` / `error.valid_values` / `error.did_you_mean` — when the error is parameter-specific - `error.retry_after` — seconds to wait before retrying (rate-limit + transient upstream) `Access-Control-Expose-Headers` lists `x-request-id` and the `X-RateLimit-*` family so browsers can read them on cross-origin responses. ## Quick Start 1. Get an API key at https://repull.dev/dashboard 2. Connect a PMS: `POST /v1/connect/{provider}` 3. List properties: `GET /v1/properties` 4. Get reservations: `GET /v1/reservations` ## Authentication All requests require a Bearer token: ``` Authorization: Bearer sk_test_YOUR_API_KEY ``` Sandbox keys start with `sk_test_`, production with `sk_live_`. ## Request Correlation (X-Request-ID) Every response carries an `X-Request-ID` header, e.g. `X-Request-ID: req_01HXY...`. Include this id in support tickets and bug reports — we can trace the full request lifecycle (auth, rate limit, handler, downstream calls, log row) from a single id. You may set the header on the inbound request to forward your own trace id; we will echo it back instead of generating a new one. Accepted format: `^[\\\\w.-]{1,128}$`. The id is also embedded in error envelopes as `request_id` so server-side log diffs work even when the response headers are stripped by an intermediate proxy. ## Rate Limits The public API enforces a per-API-key sliding-window rate limit on top of the per-tier monthly + daily-AI quotas. **Default policy:** 600 requests per 60 seconds, per API key. Sliding window — there is no fixed-minute boundary you can burst across. Every response includes: | Header | Meaning | |---|---| | `X-RateLimit-Limit` | Requests permitted in the current window. | | `X-RateLimit-Remaining` | Requests left in the current window after this call. | | `X-RateLimit-Reset` | Unix epoch (seconds) when the next slot opens. | | `X-RateLimit-Policy` | Machine-readable policy descriptor, e.g. `600;w=60`. | | `Retry-After` | Seconds to wait before retrying. **Only present on 429 responses.** | **On 429 (rate_limit_exceeded):** the response body matches the standard error envelope with `code: \"rate_limit_exceeded\"`, plus `limit`, `window_seconds`, `retry_after`, and `request_id` fields. SDKs MUST honor `Retry-After` and use exponential backoff with jitter on subsequent retries — never a tight loop. Recommended backoff: ``` sleep_ms = (Retry-After * 1000) + random(0..250) ``` Monthly + daily-AI tier quotas (`free`, `starter`, `custom`) are enforced separately and also surface as 429s; they include `tier`, `scope`, and `resets_at` fields.
|
|
5
5
|
|
|
6
6
|
The version of the OpenAPI document: 1.0.0
|
|
7
7
|
Contact: ivan@vanio.ai
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
=begin
|
|
2
2
|
#Repull API
|
|
3
3
|
|
|
4
|
-
#The unified API for vacation rental tech. Connect to 50+ PMS platforms and 4 OTA channels through one REST API. Built-in AI operations for guest communication, pricing, and listing optimization. ## Designed for AI agents Every error response on this API includes machine-parseable fields so an LLM (Claude in MCP, Cursor, Cline, GPT, etc.) can self-recover without escalating to a human: - `error.code` — stable string identifier (e.g. `invalid_params`, `rate_limit_exceeded`) - `error.message` — human-readable cause - `error.fix` — exact recovery steps (e.g. \"Pass `check_in_after` as ISO 8601: `?check_in_after=2026-01-15`\") - `error.docs_url` — link to the canonical write-up at `https://repull.dev/docs/errors/{code}` - `error.request_id` — id to correlate with server-side logs - `error.field` / `error.value_received` / `error.valid_values` / `error.did_you_mean` — when the error is parameter-specific - `error.retry_after` — seconds to wait before retrying (rate-limit + transient upstream) `Access-Control-Expose-Headers` lists `x-request-id` and the `X-RateLimit-*` family so browsers can read them on cross-origin responses. ## Quick Start 1. Get an API key at https://repull.dev/dashboard 2. Connect a PMS: `POST /v1/connect/{provider}` 3. List properties: `GET /v1/properties` 4. Get reservations: `GET /v1/reservations` ## Authentication All requests require a Bearer token: ``` Authorization: Bearer sk_test_YOUR_API_KEY ``` Sandbox keys start with `sk_test_`, production with `sk_live_`. ## Request Correlation (X-Request-ID) Every response carries an `X-Request-ID` header, e.g. `X-Request-ID: req_01HXY...`. Include this id in support tickets and bug reports — we can trace the full request lifecycle (auth, rate limit, handler, downstream calls, log row) from a single id. You may set the header on the inbound request to forward your own trace id; we will echo it back instead of generating a new one. Accepted format: `^[\\\\w.-]{1,128}$`. The id is also embedded in error envelopes as `request_id` so server-side log diffs work even when the response headers are stripped by an intermediate proxy. ## Rate Limits The public API enforces a per-API-key sliding-window rate limit on top of the per-tier monthly + daily-AI quotas. **Default policy:** 600 requests per 60 seconds, per API key. Sliding window — there is no fixed-minute boundary you can burst across. Every response includes: | Header | Meaning | |---|---| | `X-RateLimit-Limit` | Requests permitted in the current window. | | `X-RateLimit-Remaining` | Requests left in the current window after this call. | | `X-RateLimit-Reset` | Unix epoch (seconds) when the next slot opens. | | `X-RateLimit-Policy` | Machine-readable policy descriptor, e.g. `600;w=60`. | | `Retry-After` | Seconds to wait before retrying. **Only present on 429 responses.** | **On 429 (rate_limit_exceeded):** the response body matches the standard error envelope with `code: \"rate_limit_exceeded\"`, plus `limit`, `window_seconds`, `retry_after`, and `request_id` fields. SDKs MUST honor `Retry-After` and use exponential backoff with jitter on subsequent retries — never a tight loop. Recommended backoff: ``` sleep_ms = (Retry-After * 1000) + random(0..250) ``` Monthly + daily-AI tier quotas (`free`, `starter`, `
|
|
4
|
+
#The unified API for vacation rental tech. Connect to 50+ PMS platforms and 4 OTA channels through one REST API. Built-in AI operations for guest communication, pricing, and listing optimization. ## Designed for AI agents Every error response on this API includes machine-parseable fields so an LLM (Claude in MCP, Cursor, Cline, GPT, etc.) can self-recover without escalating to a human: - `error.code` — stable string identifier (e.g. `invalid_params`, `rate_limit_exceeded`) - `error.message` — human-readable cause - `error.fix` — exact recovery steps (e.g. \"Pass `check_in_after` as ISO 8601: `?check_in_after=2026-01-15`\") - `error.docs_url` — link to the canonical write-up at `https://repull.dev/docs/errors/{code}` - `error.request_id` — id to correlate with server-side logs - `error.field` / `error.value_received` / `error.valid_values` / `error.did_you_mean` — when the error is parameter-specific - `error.retry_after` — seconds to wait before retrying (rate-limit + transient upstream) `Access-Control-Expose-Headers` lists `x-request-id` and the `X-RateLimit-*` family so browsers can read them on cross-origin responses. ## Quick Start 1. Get an API key at https://repull.dev/dashboard 2. Connect a PMS: `POST /v1/connect/{provider}` 3. List properties: `GET /v1/properties` 4. Get reservations: `GET /v1/reservations` ## Authentication All requests require a Bearer token: ``` Authorization: Bearer sk_test_YOUR_API_KEY ``` Sandbox keys start with `sk_test_`, production with `sk_live_`. ## Request Correlation (X-Request-ID) Every response carries an `X-Request-ID` header, e.g. `X-Request-ID: req_01HXY...`. Include this id in support tickets and bug reports — we can trace the full request lifecycle (auth, rate limit, handler, downstream calls, log row) from a single id. You may set the header on the inbound request to forward your own trace id; we will echo it back instead of generating a new one. Accepted format: `^[\\\\w.-]{1,128}$`. The id is also embedded in error envelopes as `request_id` so server-side log diffs work even when the response headers are stripped by an intermediate proxy. ## Rate Limits The public API enforces a per-API-key sliding-window rate limit on top of the per-tier monthly + daily-AI quotas. **Default policy:** 600 requests per 60 seconds, per API key. Sliding window — there is no fixed-minute boundary you can burst across. Every response includes: | Header | Meaning | |---|---| | `X-RateLimit-Limit` | Requests permitted in the current window. | | `X-RateLimit-Remaining` | Requests left in the current window after this call. | | `X-RateLimit-Reset` | Unix epoch (seconds) when the next slot opens. | | `X-RateLimit-Policy` | Machine-readable policy descriptor, e.g. `600;w=60`. | | `Retry-After` | Seconds to wait before retrying. **Only present on 429 responses.** | **On 429 (rate_limit_exceeded):** the response body matches the standard error envelope with `code: \"rate_limit_exceeded\"`, plus `limit`, `window_seconds`, `retry_after`, and `request_id` fields. SDKs MUST honor `Retry-After` and use exponential backoff with jitter on subsequent retries — never a tight loop. Recommended backoff: ``` sleep_ms = (Retry-After * 1000) + random(0..250) ``` Monthly + daily-AI tier quotas (`free`, `starter`, `custom`) are enforced separately and also surface as 429s; they include `tier`, `scope`, and `resets_at` fields.
|
|
5
5
|
|
|
6
6
|
The version of the OpenAPI document: 1.0.0
|
|
7
7
|
Contact: ivan@vanio.ai
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
=begin
|
|
2
2
|
#Repull API
|
|
3
3
|
|
|
4
|
-
#The unified API for vacation rental tech. Connect to 50+ PMS platforms and 4 OTA channels through one REST API. Built-in AI operations for guest communication, pricing, and listing optimization. ## Designed for AI agents Every error response on this API includes machine-parseable fields so an LLM (Claude in MCP, Cursor, Cline, GPT, etc.) can self-recover without escalating to a human: - `error.code` — stable string identifier (e.g. `invalid_params`, `rate_limit_exceeded`) - `error.message` — human-readable cause - `error.fix` — exact recovery steps (e.g. \"Pass `check_in_after` as ISO 8601: `?check_in_after=2026-01-15`\") - `error.docs_url` — link to the canonical write-up at `https://repull.dev/docs/errors/{code}` - `error.request_id` — id to correlate with server-side logs - `error.field` / `error.value_received` / `error.valid_values` / `error.did_you_mean` — when the error is parameter-specific - `error.retry_after` — seconds to wait before retrying (rate-limit + transient upstream) `Access-Control-Expose-Headers` lists `x-request-id` and the `X-RateLimit-*` family so browsers can read them on cross-origin responses. ## Quick Start 1. Get an API key at https://repull.dev/dashboard 2. Connect a PMS: `POST /v1/connect/{provider}` 3. List properties: `GET /v1/properties` 4. Get reservations: `GET /v1/reservations` ## Authentication All requests require a Bearer token: ``` Authorization: Bearer sk_test_YOUR_API_KEY ``` Sandbox keys start with `sk_test_`, production with `sk_live_`. ## Request Correlation (X-Request-ID) Every response carries an `X-Request-ID` header, e.g. `X-Request-ID: req_01HXY...`. Include this id in support tickets and bug reports — we can trace the full request lifecycle (auth, rate limit, handler, downstream calls, log row) from a single id. You may set the header on the inbound request to forward your own trace id; we will echo it back instead of generating a new one. Accepted format: `^[\\\\w.-]{1,128}$`. The id is also embedded in error envelopes as `request_id` so server-side log diffs work even when the response headers are stripped by an intermediate proxy. ## Rate Limits The public API enforces a per-API-key sliding-window rate limit on top of the per-tier monthly + daily-AI quotas. **Default policy:** 600 requests per 60 seconds, per API key. Sliding window — there is no fixed-minute boundary you can burst across. Every response includes: | Header | Meaning | |---|---| | `X-RateLimit-Limit` | Requests permitted in the current window. | | `X-RateLimit-Remaining` | Requests left in the current window after this call. | | `X-RateLimit-Reset` | Unix epoch (seconds) when the next slot opens. | | `X-RateLimit-Policy` | Machine-readable policy descriptor, e.g. `600;w=60`. | | `Retry-After` | Seconds to wait before retrying. **Only present on 429 responses.** | **On 429 (rate_limit_exceeded):** the response body matches the standard error envelope with `code: \"rate_limit_exceeded\"`, plus `limit`, `window_seconds`, `retry_after`, and `request_id` fields. SDKs MUST honor `Retry-After` and use exponential backoff with jitter on subsequent retries — never a tight loop. Recommended backoff: ``` sleep_ms = (Retry-After * 1000) + random(0..250) ``` Monthly + daily-AI tier quotas (`free`, `starter`, `
|
|
4
|
+
#The unified API for vacation rental tech. Connect to 50+ PMS platforms and 4 OTA channels through one REST API. Built-in AI operations for guest communication, pricing, and listing optimization. ## Designed for AI agents Every error response on this API includes machine-parseable fields so an LLM (Claude in MCP, Cursor, Cline, GPT, etc.) can self-recover without escalating to a human: - `error.code` — stable string identifier (e.g. `invalid_params`, `rate_limit_exceeded`) - `error.message` — human-readable cause - `error.fix` — exact recovery steps (e.g. \"Pass `check_in_after` as ISO 8601: `?check_in_after=2026-01-15`\") - `error.docs_url` — link to the canonical write-up at `https://repull.dev/docs/errors/{code}` - `error.request_id` — id to correlate with server-side logs - `error.field` / `error.value_received` / `error.valid_values` / `error.did_you_mean` — when the error is parameter-specific - `error.retry_after` — seconds to wait before retrying (rate-limit + transient upstream) `Access-Control-Expose-Headers` lists `x-request-id` and the `X-RateLimit-*` family so browsers can read them on cross-origin responses. ## Quick Start 1. Get an API key at https://repull.dev/dashboard 2. Connect a PMS: `POST /v1/connect/{provider}` 3. List properties: `GET /v1/properties` 4. Get reservations: `GET /v1/reservations` ## Authentication All requests require a Bearer token: ``` Authorization: Bearer sk_test_YOUR_API_KEY ``` Sandbox keys start with `sk_test_`, production with `sk_live_`. ## Request Correlation (X-Request-ID) Every response carries an `X-Request-ID` header, e.g. `X-Request-ID: req_01HXY...`. Include this id in support tickets and bug reports — we can trace the full request lifecycle (auth, rate limit, handler, downstream calls, log row) from a single id. You may set the header on the inbound request to forward your own trace id; we will echo it back instead of generating a new one. Accepted format: `^[\\\\w.-]{1,128}$`. The id is also embedded in error envelopes as `request_id` so server-side log diffs work even when the response headers are stripped by an intermediate proxy. ## Rate Limits The public API enforces a per-API-key sliding-window rate limit on top of the per-tier monthly + daily-AI quotas. **Default policy:** 600 requests per 60 seconds, per API key. Sliding window — there is no fixed-minute boundary you can burst across. Every response includes: | Header | Meaning | |---|---| | `X-RateLimit-Limit` | Requests permitted in the current window. | | `X-RateLimit-Remaining` | Requests left in the current window after this call. | | `X-RateLimit-Reset` | Unix epoch (seconds) when the next slot opens. | | `X-RateLimit-Policy` | Machine-readable policy descriptor, e.g. `600;w=60`. | | `Retry-After` | Seconds to wait before retrying. **Only present on 429 responses.** | **On 429 (rate_limit_exceeded):** the response body matches the standard error envelope with `code: \"rate_limit_exceeded\"`, plus `limit`, `window_seconds`, `retry_after`, and `request_id` fields. SDKs MUST honor `Retry-After` and use exponential backoff with jitter on subsequent retries — never a tight loop. Recommended backoff: ``` sleep_ms = (Retry-After * 1000) + random(0..250) ``` Monthly + daily-AI tier quotas (`free`, `starter`, `custom`) are enforced separately and also surface as 429s; they include `tier`, `scope`, and `resets_at` fields.
|
|
5
5
|
|
|
6
6
|
The version of the OpenAPI document: 1.0.0
|
|
7
7
|
Contact: ivan@vanio.ai
|