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
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
#Repull API
|
|
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`, `custom`) are enforced separately and also surface as 429s; they include `tier`, `scope`, and `resets_at` fields.
|
|
5
|
+
|
|
6
|
+
The version of the OpenAPI document: 1.0.0
|
|
7
|
+
Contact: ivan@vanio.ai
|
|
8
|
+
Generated by: https://openapi-generator.tech
|
|
9
|
+
Generator version: 7.22.0
|
|
10
|
+
|
|
11
|
+
=end
|
|
12
|
+
|
|
13
|
+
require 'cgi'
|
|
14
|
+
|
|
15
|
+
module Repull
|
|
16
|
+
class KVApi
|
|
17
|
+
attr_accessor :api_client
|
|
18
|
+
|
|
19
|
+
def initialize(api_client = ApiClient.default)
|
|
20
|
+
@api_client = api_client
|
|
21
|
+
end
|
|
22
|
+
# Clear KV entries by prefix
|
|
23
|
+
# Bulk-deletes every key in the project whose name starts with `prefix`. The `prefix` parameter is required — there is no \"delete every key in this project\" shortcut; pass an empty `prefix` is rejected with 422 to prevent accidental wipes. Returns the number of rows removed.
|
|
24
|
+
# @param prefix [String] Required. Keys starting with this string are deleted.
|
|
25
|
+
# @param [Hash] opts the optional parameters
|
|
26
|
+
# @option opts [String] :project_id (default to 'default')
|
|
27
|
+
# @return [ClearKv200Response]
|
|
28
|
+
def clear_kv(prefix, opts = {})
|
|
29
|
+
data, _status_code, _headers = clear_kv_with_http_info(prefix, opts)
|
|
30
|
+
data
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Clear KV entries by prefix
|
|
34
|
+
# Bulk-deletes every key in the project whose name starts with `prefix`. The `prefix` parameter is required — there is no \"delete every key in this project\" shortcut; pass an empty `prefix` is rejected with 422 to prevent accidental wipes. Returns the number of rows removed.
|
|
35
|
+
# @param prefix [String] Required. Keys starting with this string are deleted.
|
|
36
|
+
# @param [Hash] opts the optional parameters
|
|
37
|
+
# @option opts [String] :project_id (default to 'default')
|
|
38
|
+
# @return [Array<(ClearKv200Response, Integer, Hash)>] ClearKv200Response data, response status code and response headers
|
|
39
|
+
def clear_kv_with_http_info(prefix, opts = {})
|
|
40
|
+
if @api_client.config.debugging
|
|
41
|
+
@api_client.config.logger.debug 'Calling API: KVApi.clear_kv ...'
|
|
42
|
+
end
|
|
43
|
+
# verify the required parameter 'prefix' is set
|
|
44
|
+
if @api_client.config.client_side_validation && prefix.nil?
|
|
45
|
+
fail ArgumentError, "Missing the required parameter 'prefix' when calling KVApi.clear_kv"
|
|
46
|
+
end
|
|
47
|
+
# resource path
|
|
48
|
+
local_var_path = '/v1/kv'
|
|
49
|
+
|
|
50
|
+
# query parameters
|
|
51
|
+
query_params = opts[:query_params] || {}
|
|
52
|
+
query_params[:'prefix'] = prefix
|
|
53
|
+
query_params[:'project_id'] = opts[:'project_id'] if !opts[:'project_id'].nil?
|
|
54
|
+
|
|
55
|
+
# header parameters
|
|
56
|
+
header_params = opts[:header_params] || {}
|
|
57
|
+
# HTTP header 'Accept' (if needed)
|
|
58
|
+
header_params['Accept'] = @api_client.select_header_accept(['application/json']) unless header_params['Accept']
|
|
59
|
+
|
|
60
|
+
# form parameters
|
|
61
|
+
form_params = opts[:form_params] || {}
|
|
62
|
+
|
|
63
|
+
# http body (model)
|
|
64
|
+
post_body = opts[:debug_body]
|
|
65
|
+
|
|
66
|
+
# return_type
|
|
67
|
+
return_type = opts[:debug_return_type] || 'ClearKv200Response'
|
|
68
|
+
|
|
69
|
+
# auth_names
|
|
70
|
+
auth_names = opts[:debug_auth_names] || ['bearerAuth']
|
|
71
|
+
|
|
72
|
+
new_options = opts.merge(
|
|
73
|
+
:operation => :"KVApi.clear_kv",
|
|
74
|
+
:header_params => header_params,
|
|
75
|
+
:query_params => query_params,
|
|
76
|
+
:form_params => form_params,
|
|
77
|
+
:body => post_body,
|
|
78
|
+
:auth_names => auth_names,
|
|
79
|
+
:return_type => return_type
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
data, status_code, headers = @api_client.call_api(:DELETE, local_var_path, new_options)
|
|
83
|
+
if @api_client.config.debugging
|
|
84
|
+
@api_client.config.logger.debug "API called: KVApi#clear_kv\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
|
|
85
|
+
end
|
|
86
|
+
return data, status_code, headers
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Delete a KV entry
|
|
90
|
+
# Removes a single key. Returns `{ deleted: true }` if the row was present, `{ deleted: false }` if it was already absent — both are 200 (idempotent).
|
|
91
|
+
# @param key [String]
|
|
92
|
+
# @param [Hash] opts the optional parameters
|
|
93
|
+
# @option opts [String] :project_id (default to 'default')
|
|
94
|
+
# @return [DeleteKv200Response]
|
|
95
|
+
def delete_kv(key, opts = {})
|
|
96
|
+
data, _status_code, _headers = delete_kv_with_http_info(key, opts)
|
|
97
|
+
data
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Delete a KV entry
|
|
101
|
+
# Removes a single key. Returns `{ deleted: true }` if the row was present, `{ deleted: false }` if it was already absent — both are 200 (idempotent).
|
|
102
|
+
# @param key [String]
|
|
103
|
+
# @param [Hash] opts the optional parameters
|
|
104
|
+
# @option opts [String] :project_id (default to 'default')
|
|
105
|
+
# @return [Array<(DeleteKv200Response, Integer, Hash)>] DeleteKv200Response data, response status code and response headers
|
|
106
|
+
def delete_kv_with_http_info(key, opts = {})
|
|
107
|
+
if @api_client.config.debugging
|
|
108
|
+
@api_client.config.logger.debug 'Calling API: KVApi.delete_kv ...'
|
|
109
|
+
end
|
|
110
|
+
# verify the required parameter 'key' is set
|
|
111
|
+
if @api_client.config.client_side_validation && key.nil?
|
|
112
|
+
fail ArgumentError, "Missing the required parameter 'key' when calling KVApi.delete_kv"
|
|
113
|
+
end
|
|
114
|
+
# resource path
|
|
115
|
+
local_var_path = '/v1/kv/{key}'.sub('{key}', CGI.escape(key.to_s))
|
|
116
|
+
|
|
117
|
+
# query parameters
|
|
118
|
+
query_params = opts[:query_params] || {}
|
|
119
|
+
query_params[:'project_id'] = opts[:'project_id'] if !opts[:'project_id'].nil?
|
|
120
|
+
|
|
121
|
+
# header parameters
|
|
122
|
+
header_params = opts[:header_params] || {}
|
|
123
|
+
# HTTP header 'Accept' (if needed)
|
|
124
|
+
header_params['Accept'] = @api_client.select_header_accept(['application/json']) unless header_params['Accept']
|
|
125
|
+
|
|
126
|
+
# form parameters
|
|
127
|
+
form_params = opts[:form_params] || {}
|
|
128
|
+
|
|
129
|
+
# http body (model)
|
|
130
|
+
post_body = opts[:debug_body]
|
|
131
|
+
|
|
132
|
+
# return_type
|
|
133
|
+
return_type = opts[:debug_return_type] || 'DeleteKv200Response'
|
|
134
|
+
|
|
135
|
+
# auth_names
|
|
136
|
+
auth_names = opts[:debug_auth_names] || ['bearerAuth']
|
|
137
|
+
|
|
138
|
+
new_options = opts.merge(
|
|
139
|
+
:operation => :"KVApi.delete_kv",
|
|
140
|
+
:header_params => header_params,
|
|
141
|
+
:query_params => query_params,
|
|
142
|
+
:form_params => form_params,
|
|
143
|
+
:body => post_body,
|
|
144
|
+
:auth_names => auth_names,
|
|
145
|
+
:return_type => return_type
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
data, status_code, headers = @api_client.call_api(:DELETE, local_var_path, new_options)
|
|
149
|
+
if @api_client.config.debugging
|
|
150
|
+
@api_client.config.logger.debug "API called: KVApi#delete_kv\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
|
|
151
|
+
end
|
|
152
|
+
return data, status_code, headers
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Get a KV entry
|
|
156
|
+
# Fetches a single key. Returns 404 when the key does not exist OR has expired (rows past `ttl_at` are filtered from reads). Cross-tenant lookups also return 404 — the API never reveals existence of another customer's keys.
|
|
157
|
+
# @param key [String] KV key. URL-encode `/`, `:`, etc. so they survive routing.
|
|
158
|
+
# @param [Hash] opts the optional parameters
|
|
159
|
+
# @option opts [String] :project_id (default to 'default')
|
|
160
|
+
# @return [ListKv200ResponseDataInner]
|
|
161
|
+
def get_kv(key, opts = {})
|
|
162
|
+
data, _status_code, _headers = get_kv_with_http_info(key, opts)
|
|
163
|
+
data
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Get a KV entry
|
|
167
|
+
# Fetches a single key. Returns 404 when the key does not exist OR has expired (rows past `ttl_at` are filtered from reads). Cross-tenant lookups also return 404 — the API never reveals existence of another customer's keys.
|
|
168
|
+
# @param key [String] KV key. URL-encode `/`, `:`, etc. so they survive routing.
|
|
169
|
+
# @param [Hash] opts the optional parameters
|
|
170
|
+
# @option opts [String] :project_id (default to 'default')
|
|
171
|
+
# @return [Array<(ListKv200ResponseDataInner, Integer, Hash)>] ListKv200ResponseDataInner data, response status code and response headers
|
|
172
|
+
def get_kv_with_http_info(key, opts = {})
|
|
173
|
+
if @api_client.config.debugging
|
|
174
|
+
@api_client.config.logger.debug 'Calling API: KVApi.get_kv ...'
|
|
175
|
+
end
|
|
176
|
+
# verify the required parameter 'key' is set
|
|
177
|
+
if @api_client.config.client_side_validation && key.nil?
|
|
178
|
+
fail ArgumentError, "Missing the required parameter 'key' when calling KVApi.get_kv"
|
|
179
|
+
end
|
|
180
|
+
# resource path
|
|
181
|
+
local_var_path = '/v1/kv/{key}'.sub('{key}', CGI.escape(key.to_s))
|
|
182
|
+
|
|
183
|
+
# query parameters
|
|
184
|
+
query_params = opts[:query_params] || {}
|
|
185
|
+
query_params[:'project_id'] = opts[:'project_id'] if !opts[:'project_id'].nil?
|
|
186
|
+
|
|
187
|
+
# header parameters
|
|
188
|
+
header_params = opts[:header_params] || {}
|
|
189
|
+
# HTTP header 'Accept' (if needed)
|
|
190
|
+
header_params['Accept'] = @api_client.select_header_accept(['application/json']) unless header_params['Accept']
|
|
191
|
+
|
|
192
|
+
# form parameters
|
|
193
|
+
form_params = opts[:form_params] || {}
|
|
194
|
+
|
|
195
|
+
# http body (model)
|
|
196
|
+
post_body = opts[:debug_body]
|
|
197
|
+
|
|
198
|
+
# return_type
|
|
199
|
+
return_type = opts[:debug_return_type] || 'ListKv200ResponseDataInner'
|
|
200
|
+
|
|
201
|
+
# auth_names
|
|
202
|
+
auth_names = opts[:debug_auth_names] || ['bearerAuth']
|
|
203
|
+
|
|
204
|
+
new_options = opts.merge(
|
|
205
|
+
:operation => :"KVApi.get_kv",
|
|
206
|
+
:header_params => header_params,
|
|
207
|
+
:query_params => query_params,
|
|
208
|
+
:form_params => form_params,
|
|
209
|
+
:body => post_body,
|
|
210
|
+
:auth_names => auth_names,
|
|
211
|
+
:return_type => return_type
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
data, status_code, headers = @api_client.call_api(:GET, local_var_path, new_options)
|
|
215
|
+
if @api_client.config.debugging
|
|
216
|
+
@api_client.config.logger.debug "API called: KVApi#get_kv\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
|
|
217
|
+
end
|
|
218
|
+
return data, status_code, headers
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# List KV entries
|
|
222
|
+
# Returns every non-expired key-value row in the given project, sorted ascending by key. Use `prefix` to scope to a key namespace (e.g. `prefix=user:42:` to fetch all entries for one user). Hard cap of 1,000 rows per response — for projects approaching that, paginate by walking prefix buckets.
|
|
223
|
+
# @param [Hash] opts the optional parameters
|
|
224
|
+
# @option opts [String] :project_id Project namespace. Defaults to `default`. Free-form string the customer chooses (typically the Studio project id). (default to 'default')
|
|
225
|
+
# @option opts [String] :prefix Restrict to keys starting with this string. `LIKE` wildcards (`%`, `_`) are escaped — pass them literally.
|
|
226
|
+
# @return [ListKv200Response]
|
|
227
|
+
def list_kv(opts = {})
|
|
228
|
+
data, _status_code, _headers = list_kv_with_http_info(opts)
|
|
229
|
+
data
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# List KV entries
|
|
233
|
+
# Returns every non-expired key-value row in the given project, sorted ascending by key. Use `prefix` to scope to a key namespace (e.g. `prefix=user:42:` to fetch all entries for one user). Hard cap of 1,000 rows per response — for projects approaching that, paginate by walking prefix buckets.
|
|
234
|
+
# @param [Hash] opts the optional parameters
|
|
235
|
+
# @option opts [String] :project_id Project namespace. Defaults to `default`. Free-form string the customer chooses (typically the Studio project id). (default to 'default')
|
|
236
|
+
# @option opts [String] :prefix Restrict to keys starting with this string. `LIKE` wildcards (`%`, `_`) are escaped — pass them literally.
|
|
237
|
+
# @return [Array<(ListKv200Response, Integer, Hash)>] ListKv200Response data, response status code and response headers
|
|
238
|
+
def list_kv_with_http_info(opts = {})
|
|
239
|
+
if @api_client.config.debugging
|
|
240
|
+
@api_client.config.logger.debug 'Calling API: KVApi.list_kv ...'
|
|
241
|
+
end
|
|
242
|
+
# resource path
|
|
243
|
+
local_var_path = '/v1/kv'
|
|
244
|
+
|
|
245
|
+
# query parameters
|
|
246
|
+
query_params = opts[:query_params] || {}
|
|
247
|
+
query_params[:'project_id'] = opts[:'project_id'] if !opts[:'project_id'].nil?
|
|
248
|
+
query_params[:'prefix'] = opts[:'prefix'] if !opts[:'prefix'].nil?
|
|
249
|
+
|
|
250
|
+
# header parameters
|
|
251
|
+
header_params = opts[:header_params] || {}
|
|
252
|
+
# HTTP header 'Accept' (if needed)
|
|
253
|
+
header_params['Accept'] = @api_client.select_header_accept(['application/json']) unless header_params['Accept']
|
|
254
|
+
|
|
255
|
+
# form parameters
|
|
256
|
+
form_params = opts[:form_params] || {}
|
|
257
|
+
|
|
258
|
+
# http body (model)
|
|
259
|
+
post_body = opts[:debug_body]
|
|
260
|
+
|
|
261
|
+
# return_type
|
|
262
|
+
return_type = opts[:debug_return_type] || 'ListKv200Response'
|
|
263
|
+
|
|
264
|
+
# auth_names
|
|
265
|
+
auth_names = opts[:debug_auth_names] || ['bearerAuth']
|
|
266
|
+
|
|
267
|
+
new_options = opts.merge(
|
|
268
|
+
:operation => :"KVApi.list_kv",
|
|
269
|
+
:header_params => header_params,
|
|
270
|
+
:query_params => query_params,
|
|
271
|
+
:form_params => form_params,
|
|
272
|
+
:body => post_body,
|
|
273
|
+
:auth_names => auth_names,
|
|
274
|
+
:return_type => return_type
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
data, status_code, headers = @api_client.call_api(:GET, local_var_path, new_options)
|
|
278
|
+
if @api_client.config.debugging
|
|
279
|
+
@api_client.config.logger.debug "API called: KVApi#list_kv\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
|
|
280
|
+
end
|
|
281
|
+
return data, status_code, headers
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# Set a KV entry
|
|
285
|
+
# Upserts a key. The full row is replaced — there is no partial update. Pass `ttl_seconds` (positive integer) to auto-expire the row; omit for no expiry. **Caps:** 64 KiB per row (key bytes + value JSON bytes), 1 MiB per customer (sum across ALL projects/keys). Over either cap returns 413.
|
|
286
|
+
# @param key [String]
|
|
287
|
+
# @param set_kv_request [SetKvRequest]
|
|
288
|
+
# @param [Hash] opts the optional parameters
|
|
289
|
+
# @option opts [String] :project_id (default to 'default')
|
|
290
|
+
# @return [ListKv200ResponseDataInner]
|
|
291
|
+
def set_kv(key, set_kv_request, opts = {})
|
|
292
|
+
data, _status_code, _headers = set_kv_with_http_info(key, set_kv_request, opts)
|
|
293
|
+
data
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
# Set a KV entry
|
|
297
|
+
# Upserts a key. The full row is replaced — there is no partial update. Pass `ttl_seconds` (positive integer) to auto-expire the row; omit for no expiry. **Caps:** 64 KiB per row (key bytes + value JSON bytes), 1 MiB per customer (sum across ALL projects/keys). Over either cap returns 413.
|
|
298
|
+
# @param key [String]
|
|
299
|
+
# @param set_kv_request [SetKvRequest]
|
|
300
|
+
# @param [Hash] opts the optional parameters
|
|
301
|
+
# @option opts [String] :project_id (default to 'default')
|
|
302
|
+
# @return [Array<(ListKv200ResponseDataInner, Integer, Hash)>] ListKv200ResponseDataInner data, response status code and response headers
|
|
303
|
+
def set_kv_with_http_info(key, set_kv_request, opts = {})
|
|
304
|
+
if @api_client.config.debugging
|
|
305
|
+
@api_client.config.logger.debug 'Calling API: KVApi.set_kv ...'
|
|
306
|
+
end
|
|
307
|
+
# verify the required parameter 'key' is set
|
|
308
|
+
if @api_client.config.client_side_validation && key.nil?
|
|
309
|
+
fail ArgumentError, "Missing the required parameter 'key' when calling KVApi.set_kv"
|
|
310
|
+
end
|
|
311
|
+
# verify the required parameter 'set_kv_request' is set
|
|
312
|
+
if @api_client.config.client_side_validation && set_kv_request.nil?
|
|
313
|
+
fail ArgumentError, "Missing the required parameter 'set_kv_request' when calling KVApi.set_kv"
|
|
314
|
+
end
|
|
315
|
+
# resource path
|
|
316
|
+
local_var_path = '/v1/kv/{key}'.sub('{key}', CGI.escape(key.to_s))
|
|
317
|
+
|
|
318
|
+
# query parameters
|
|
319
|
+
query_params = opts[:query_params] || {}
|
|
320
|
+
query_params[:'project_id'] = opts[:'project_id'] if !opts[:'project_id'].nil?
|
|
321
|
+
|
|
322
|
+
# header parameters
|
|
323
|
+
header_params = opts[:header_params] || {}
|
|
324
|
+
# HTTP header 'Accept' (if needed)
|
|
325
|
+
header_params['Accept'] = @api_client.select_header_accept(['application/json']) unless header_params['Accept']
|
|
326
|
+
# HTTP header 'Content-Type'
|
|
327
|
+
content_type = @api_client.select_header_content_type(['application/json'])
|
|
328
|
+
if !content_type.nil?
|
|
329
|
+
header_params['Content-Type'] = content_type
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
# form parameters
|
|
333
|
+
form_params = opts[:form_params] || {}
|
|
334
|
+
|
|
335
|
+
# http body (model)
|
|
336
|
+
post_body = opts[:debug_body] || @api_client.object_to_http_body(set_kv_request)
|
|
337
|
+
|
|
338
|
+
# return_type
|
|
339
|
+
return_type = opts[:debug_return_type] || 'ListKv200ResponseDataInner'
|
|
340
|
+
|
|
341
|
+
# auth_names
|
|
342
|
+
auth_names = opts[:debug_auth_names] || ['bearerAuth']
|
|
343
|
+
|
|
344
|
+
new_options = opts.merge(
|
|
345
|
+
:operation => :"KVApi.set_kv",
|
|
346
|
+
:header_params => header_params,
|
|
347
|
+
:query_params => query_params,
|
|
348
|
+
:form_params => form_params,
|
|
349
|
+
:body => post_body,
|
|
350
|
+
:auth_names => auth_names,
|
|
351
|
+
:return_type => return_type
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
data, status_code, headers = @api_client.call_api(:PUT, local_var_path, new_options)
|
|
355
|
+
if @api_client.config.debugging
|
|
356
|
+
@api_client.config.logger.debug "API called: KVApi#set_kv\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
|
|
357
|
+
end
|
|
358
|
+
return data, status_code, headers
|
|
359
|
+
end
|
|
360
|
+
end
|
|
361
|
+
end
|
|
@@ -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
|
|
@@ -88,7 +88,7 @@ module Repull
|
|
|
88
88
|
end
|
|
89
89
|
|
|
90
90
|
# AI-generate listing content
|
|
91
|
-
# Generate guest-facing copy (title, summary, description, amenities, etc.) for a listing using
|
|
91
|
+
# Generate guest-facing copy (title, summary, description, amenities, etc.) for a listing using Repull AI. When `photos` are provided the vision model is used for photo-grounded copy. Persists into the listing by default.
|
|
92
92
|
# @param id [Integer]
|
|
93
93
|
# @param [Hash] opts the optional parameters
|
|
94
94
|
# @option opts [ListingGenerateContentRequest] :listing_generate_content_request
|
|
@@ -99,7 +99,7 @@ module Repull
|
|
|
99
99
|
end
|
|
100
100
|
|
|
101
101
|
# AI-generate listing content
|
|
102
|
-
# Generate guest-facing copy (title, summary, description, amenities, etc.) for a listing using
|
|
102
|
+
# Generate guest-facing copy (title, summary, description, amenities, etc.) for a listing using Repull AI. When `photos` are provided the vision model is used for photo-grounded copy. Persists into the listing by default.
|
|
103
103
|
# @param id [Integer]
|
|
104
104
|
# @param [Hash] opts the optional parameters
|
|
105
105
|
# @option opts [ListingGenerateContentRequest] :listing_generate_content_request
|
|
@@ -158,10 +158,11 @@ module Repull
|
|
|
158
158
|
end
|
|
159
159
|
|
|
160
160
|
# Get a listing
|
|
161
|
-
# Fetch a single listing by id. Returns the same shape as one element of the `GET /v1/listings` response, so you can bind the result to the same model. Cross-tenant access (a listing that belongs to a different workspace) returns 404 — never 403, never reveals the listing's existence.
|
|
161
|
+
# Fetch a single listing by id. Returns the same shape as one element of the `GET /v1/listings` response, so you can bind the result to the same model. Cross-tenant access (a listing that belongs to a different workspace) returns 404 — never 403, never reveals the listing's existence. **Optional expansions:** Pass `?include=amenities` to enrich the response with the listing's amenity rows (`[]` when the listing has none). Pass `?include=content` for the rich content slab (summary, description, space, house rules, etc. — sourced from `listings_descriptions` for the `en` locale; `null` when no row is stored). Pass `?include=details` for the structural slab (bedrooms, bathrooms, person capacity, check-in window, wifi, house manual, etc.; `null` when no row is stored). Combine comma-separated, e.g. `?include=amenities,content,details`. The default response stays lean; consumers must opt in.
|
|
162
162
|
# @param id [Integer] Repull listing id
|
|
163
163
|
# @param [Hash] opts the optional parameters
|
|
164
164
|
# @option opts [String] :x_schema Apply a custom or built-in schema to transform the response. Built-in: `native` (default), `calry`, `calry-v1`. Custom: any schema name created via `POST /v1/schema/custom`. Unknown / inactive schema names fall back to `native`.
|
|
165
|
+
# @option opts [String] :include Comma-separated optional expansions. Currently supported: `amenities`, `content`, `details`. Unknown values return 422 with a `valid_values` envelope.
|
|
165
166
|
# @return [Listing]
|
|
166
167
|
def get_listing(id, opts = {})
|
|
167
168
|
data, _status_code, _headers = get_listing_with_http_info(id, opts)
|
|
@@ -169,10 +170,11 @@ module Repull
|
|
|
169
170
|
end
|
|
170
171
|
|
|
171
172
|
# Get a listing
|
|
172
|
-
# Fetch a single listing by id. Returns the same shape as one element of the `GET /v1/listings` response, so you can bind the result to the same model. Cross-tenant access (a listing that belongs to a different workspace) returns 404 — never 403, never reveals the listing's existence.
|
|
173
|
+
# Fetch a single listing by id. Returns the same shape as one element of the `GET /v1/listings` response, so you can bind the result to the same model. Cross-tenant access (a listing that belongs to a different workspace) returns 404 — never 403, never reveals the listing's existence. **Optional expansions:** Pass `?include=amenities` to enrich the response with the listing's amenity rows (`[]` when the listing has none). Pass `?include=content` for the rich content slab (summary, description, space, house rules, etc. — sourced from `listings_descriptions` for the `en` locale; `null` when no row is stored). Pass `?include=details` for the structural slab (bedrooms, bathrooms, person capacity, check-in window, wifi, house manual, etc.; `null` when no row is stored). Combine comma-separated, e.g. `?include=amenities,content,details`. The default response stays lean; consumers must opt in.
|
|
173
174
|
# @param id [Integer] Repull listing id
|
|
174
175
|
# @param [Hash] opts the optional parameters
|
|
175
176
|
# @option opts [String] :x_schema Apply a custom or built-in schema to transform the response. Built-in: `native` (default), `calry`, `calry-v1`. Custom: any schema name created via `POST /v1/schema/custom`. Unknown / inactive schema names fall back to `native`.
|
|
177
|
+
# @option opts [String] :include Comma-separated optional expansions. Currently supported: `amenities`, `content`, `details`. Unknown values return 422 with a `valid_values` envelope.
|
|
176
178
|
# @return [Array<(Listing, Integer, Hash)>] Listing data, response status code and response headers
|
|
177
179
|
def get_listing_with_http_info(id, opts = {})
|
|
178
180
|
if @api_client.config.debugging
|
|
@@ -187,6 +189,7 @@ module Repull
|
|
|
187
189
|
|
|
188
190
|
# query parameters
|
|
189
191
|
query_params = opts[:query_params] || {}
|
|
192
|
+
query_params[:'include'] = opts[:'include'] if !opts[:'include'].nil?
|
|
190
193
|
|
|
191
194
|
# header parameters
|
|
192
195
|
header_params = opts[:header_params] || {}
|
|
@@ -224,7 +227,7 @@ module Repull
|
|
|
224
227
|
end
|
|
225
228
|
|
|
226
229
|
# Per-channel publish status
|
|
227
|
-
# Returns
|
|
230
|
+
# Returns connection state and sync activity per channel. `channels` is sync activity (empty until first push). `connections` is connection state (populated as soon as a channel is linked). Recommended polling cadence: at most once per 30s per listing — for bulk views, prefer `GET /v1/listings` and filter client-side.
|
|
228
231
|
# @param id [Integer]
|
|
229
232
|
# @param [Hash] opts the optional parameters
|
|
230
233
|
# @return [ListingPublishStatusResponse]
|
|
@@ -234,7 +237,7 @@ module Repull
|
|
|
234
237
|
end
|
|
235
238
|
|
|
236
239
|
# Per-channel publish status
|
|
237
|
-
# Returns
|
|
240
|
+
# Returns connection state and sync activity per channel. `channels` is sync activity (empty until first push). `connections` is connection state (populated as soon as a channel is linked). Recommended polling cadence: at most once per 30s per listing — for bulk views, prefer `GET /v1/listings` and filter client-side.
|
|
238
241
|
# @param id [Integer]
|
|
239
242
|
# @param [Hash] opts the optional parameters
|
|
240
243
|
# @return [Array<(ListingPublishStatusResponse, Integer, Hash)>] ListingPublishStatusResponse data, response status code and response headers
|
|
@@ -287,14 +290,16 @@ module Repull
|
|
|
287
290
|
end
|
|
288
291
|
|
|
289
292
|
# List listings
|
|
290
|
-
# Cursor-paginated list of listings owned by the authenticated workspace. Use `pagination.nextCursor` from one response as the `cursor` query param of the next request to walk the full set. Filters: `q` (substring on name/street/city), `status`, `channel`.
|
|
293
|
+
# Cursor-paginated list of listings owned by the authenticated workspace. Use `pagination.nextCursor` from one response as the `cursor` query param of the next request to walk the full set. `?offset=` is also accepted as a first-class alias for shallow paging (0..10000) — see the `offset` parameter below. Mutually exclusive with `cursor`. Filters: `q` (substring on name/street/city), `status`, `channel`. **Optional expansions:** Pass `?include=content` to enrich each row with the rich content slab (summary, description, space, house rules, etc. — sourced from `listings_descriptions` for the `en` locale). Pass `?include=details` for the structural slab (bedrooms, bathrooms, person capacity, check-in window, wifi, house manual, etc.). Both default to `null` per row when the underlying `listings_descriptions` / `listings_details` row is missing — distinct from the field being absent (which signals the expansion was not requested). Combine comma-separated, e.g. `?include=content,details`. The default response stays lean; consumers must opt in.
|
|
291
294
|
# @param [Hash] opts the optional parameters
|
|
292
295
|
# @option opts [String] :x_schema Apply a custom or built-in schema to transform the response. Built-in: `native` (default), `calry`, `calry-v1`. Custom: any schema name created via `POST /v1/schema/custom`. Unknown / inactive schema names fall back to `native`.
|
|
293
296
|
# @option opts [String] :cursor Opaque cursor returned in the previous response's `pagination.nextCursor`. Omit to fetch the first page.
|
|
297
|
+
# @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)
|
|
294
298
|
# @option opts [Integer] :limit Max items per page. Hard cap is 100. (default to 20)
|
|
295
299
|
# @option opts [String] :q Case-insensitive substring search on name, street, or city.
|
|
296
300
|
# @option opts [String] :status Filter by listing status.
|
|
297
301
|
# @option opts [String] :channel Restrict to listings published on the given channel (`airbnb`, `booking`, `vrbo`, etc.). Joins through `listing_platform_links` and matches active links only.
|
|
302
|
+
# @option opts [String] :include Comma-separated optional expansions. Currently supported: `content`, `details`. Unknown values return 422 with a `valid_values` envelope. (Note: `amenities` is not yet supported on the list endpoint — use the detail endpoint to fetch amenity rows for a single listing.)
|
|
298
303
|
# @return [ListingListResponse]
|
|
299
304
|
def list_listings(opts = {})
|
|
300
305
|
data, _status_code, _headers = list_listings_with_http_info(opts)
|
|
@@ -302,19 +307,29 @@ module Repull
|
|
|
302
307
|
end
|
|
303
308
|
|
|
304
309
|
# List listings
|
|
305
|
-
# Cursor-paginated list of listings owned by the authenticated workspace. Use `pagination.nextCursor` from one response as the `cursor` query param of the next request to walk the full set. Filters: `q` (substring on name/street/city), `status`, `channel`.
|
|
310
|
+
# Cursor-paginated list of listings owned by the authenticated workspace. Use `pagination.nextCursor` from one response as the `cursor` query param of the next request to walk the full set. `?offset=` is also accepted as a first-class alias for shallow paging (0..10000) — see the `offset` parameter below. Mutually exclusive with `cursor`. Filters: `q` (substring on name/street/city), `status`, `channel`. **Optional expansions:** Pass `?include=content` to enrich each row with the rich content slab (summary, description, space, house rules, etc. — sourced from `listings_descriptions` for the `en` locale). Pass `?include=details` for the structural slab (bedrooms, bathrooms, person capacity, check-in window, wifi, house manual, etc.). Both default to `null` per row when the underlying `listings_descriptions` / `listings_details` row is missing — distinct from the field being absent (which signals the expansion was not requested). Combine comma-separated, e.g. `?include=content,details`. The default response stays lean; consumers must opt in.
|
|
306
311
|
# @param [Hash] opts the optional parameters
|
|
307
312
|
# @option opts [String] :x_schema Apply a custom or built-in schema to transform the response. Built-in: `native` (default), `calry`, `calry-v1`. Custom: any schema name created via `POST /v1/schema/custom`. Unknown / inactive schema names fall back to `native`.
|
|
308
313
|
# @option opts [String] :cursor Opaque cursor returned in the previous response's `pagination.nextCursor`. Omit to fetch the first page.
|
|
314
|
+
# @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)
|
|
309
315
|
# @option opts [Integer] :limit Max items per page. Hard cap is 100. (default to 20)
|
|
310
316
|
# @option opts [String] :q Case-insensitive substring search on name, street, or city.
|
|
311
317
|
# @option opts [String] :status Filter by listing status.
|
|
312
318
|
# @option opts [String] :channel Restrict to listings published on the given channel (`airbnb`, `booking`, `vrbo`, etc.). Joins through `listing_platform_links` and matches active links only.
|
|
319
|
+
# @option opts [String] :include Comma-separated optional expansions. Currently supported: `content`, `details`. Unknown values return 422 with a `valid_values` envelope. (Note: `amenities` is not yet supported on the list endpoint — use the detail endpoint to fetch amenity rows for a single listing.)
|
|
313
320
|
# @return [Array<(ListingListResponse, Integer, Hash)>] ListingListResponse data, response status code and response headers
|
|
314
321
|
def list_listings_with_http_info(opts = {})
|
|
315
322
|
if @api_client.config.debugging
|
|
316
323
|
@api_client.config.logger.debug 'Calling API: ListingsApi.list_listings ...'
|
|
317
324
|
end
|
|
325
|
+
if @api_client.config.client_side_validation && !opts[:'offset'].nil? && opts[:'offset'] > 10000
|
|
326
|
+
fail ArgumentError, 'invalid value for "opts[:"offset"]" when calling ListingsApi.list_listings, must be smaller than or equal to 10000.'
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
if @api_client.config.client_side_validation && !opts[:'offset'].nil? && opts[:'offset'] < 0
|
|
330
|
+
fail ArgumentError, 'invalid value for "opts[:"offset"]" when calling ListingsApi.list_listings, must be greater than or equal to 0.'
|
|
331
|
+
end
|
|
332
|
+
|
|
318
333
|
if @api_client.config.client_side_validation && !opts[:'limit'].nil? && opts[:'limit'] > 100
|
|
319
334
|
fail ArgumentError, 'invalid value for "opts[:"limit"]" when calling ListingsApi.list_listings, must be smaller than or equal to 100.'
|
|
320
335
|
end
|
|
@@ -333,10 +348,12 @@ module Repull
|
|
|
333
348
|
# query parameters
|
|
334
349
|
query_params = opts[:query_params] || {}
|
|
335
350
|
query_params[:'cursor'] = opts[:'cursor'] if !opts[:'cursor'].nil?
|
|
351
|
+
query_params[:'offset'] = opts[:'offset'] if !opts[:'offset'].nil?
|
|
336
352
|
query_params[:'limit'] = opts[:'limit'] if !opts[:'limit'].nil?
|
|
337
353
|
query_params[:'q'] = opts[:'q'] if !opts[:'q'].nil?
|
|
338
354
|
query_params[:'status'] = opts[:'status'] if !opts[:'status'].nil?
|
|
339
355
|
query_params[:'channel'] = opts[:'channel'] if !opts[:'channel'].nil?
|
|
356
|
+
query_params[:'include'] = opts[:'include'] if !opts[:'include'].nil?
|
|
340
357
|
|
|
341
358
|
# header parameters
|
|
342
359
|
header_params = opts[:header_params] || {}
|
|
@@ -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
|
|
@@ -162,12 +162,13 @@ module Repull
|
|
|
162
162
|
end
|
|
163
163
|
|
|
164
164
|
# Paginated discovery catalog
|
|
165
|
-
# Cursor-paginated, search-filterable catalog of every Atlas-tracked market the customer could expand into. Backed by the precomputed `market_summaries` table (>=5 active comps per city). Supports fuzzy `q` substring search (trigram-indexed), `country` (ISO 3166-1 alpha-2) filter, and `sort` (`listings_desc` | `name_asc`). Use the `nextCursor` from `pagination` to walk pages — the cursor is an opaque base64 token; do not parse it. `pagination.total` is the count of markets matching the current `q`/`country`/`min_listings` filter (across all pages)
|
|
165
|
+
# Cursor-paginated, search-filterable catalog of every Atlas-tracked market the customer could expand into. Backed by the precomputed `market_summaries` table (>=5 active comps per city). Supports fuzzy `q` substring search (trigram-indexed), `country` (ISO 3166-1 alpha-2) filter, and `sort` (`listings_desc` | `name_asc`). Use the `nextCursor` from `pagination` to walk pages — the cursor is an opaque base64 token; do not parse it. `?offset=` is also accepted as a first-class alias for shallow paging (0..10000) — see the `offset` parameter below. Mutually exclusive with `cursor`. `pagination.total` is the count of markets matching the current `q`/`country`/`min_listings` filter (across all pages) — same shape as every other list endpoint.
|
|
166
166
|
# @param [Hash] opts the optional parameters
|
|
167
167
|
# @option opts [String] :q Substring match on city name (case-insensitive).
|
|
168
168
|
# @option opts [String] :country ISO 3166-1 alpha-2 (e.g. `US`, `ES`).
|
|
169
169
|
# @option opts [Integer] :min_listings Minimum comp-set size — cities with fewer active comps are excluded. (default to 5)
|
|
170
170
|
# @option opts [String] :cursor Opaque cursor returned by the previous page's `pagination.nextCursor`.
|
|
171
|
+
# @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)
|
|
171
172
|
# @option opts [Integer] :limit (default to 30)
|
|
172
173
|
# @option opts [String] :sort (default to 'listings_desc')
|
|
173
174
|
# @return [MarketBrowseResponse]
|
|
@@ -177,12 +178,13 @@ module Repull
|
|
|
177
178
|
end
|
|
178
179
|
|
|
179
180
|
# Paginated discovery catalog
|
|
180
|
-
# Cursor-paginated, search-filterable catalog of every Atlas-tracked market the customer could expand into. Backed by the precomputed `market_summaries` table (>=5 active comps per city). Supports fuzzy `q` substring search (trigram-indexed), `country` (ISO 3166-1 alpha-2) filter, and `sort` (`listings_desc` | `name_asc`). Use the `nextCursor` from `pagination` to walk pages — the cursor is an opaque base64 token; do not parse it. `pagination.total` is the count of markets matching the current `q`/`country`/`min_listings` filter (across all pages)
|
|
181
|
+
# Cursor-paginated, search-filterable catalog of every Atlas-tracked market the customer could expand into. Backed by the precomputed `market_summaries` table (>=5 active comps per city). Supports fuzzy `q` substring search (trigram-indexed), `country` (ISO 3166-1 alpha-2) filter, and `sort` (`listings_desc` | `name_asc`). Use the `nextCursor` from `pagination` to walk pages — the cursor is an opaque base64 token; do not parse it. `?offset=` is also accepted as a first-class alias for shallow paging (0..10000) — see the `offset` parameter below. Mutually exclusive with `cursor`. `pagination.total` is the count of markets matching the current `q`/`country`/`min_listings` filter (across all pages) — same shape as every other list endpoint.
|
|
181
182
|
# @param [Hash] opts the optional parameters
|
|
182
183
|
# @option opts [String] :q Substring match on city name (case-insensitive).
|
|
183
184
|
# @option opts [String] :country ISO 3166-1 alpha-2 (e.g. `US`, `ES`).
|
|
184
185
|
# @option opts [Integer] :min_listings Minimum comp-set size — cities with fewer active comps are excluded. (default to 5)
|
|
185
186
|
# @option opts [String] :cursor Opaque cursor returned by the previous page's `pagination.nextCursor`.
|
|
187
|
+
# @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)
|
|
186
188
|
# @option opts [Integer] :limit (default to 30)
|
|
187
189
|
# @option opts [String] :sort (default to 'listings_desc')
|
|
188
190
|
# @return [Array<(MarketBrowseResponse, Integer, Hash)>] MarketBrowseResponse data, response status code and response headers
|
|
@@ -202,6 +204,14 @@ module Repull
|
|
|
202
204
|
fail ArgumentError, 'invalid value for "opts[:"min_listings"]" when calling MarketsApi.list_market_browse, must be greater than or equal to 0.'
|
|
203
205
|
end
|
|
204
206
|
|
|
207
|
+
if @api_client.config.client_side_validation && !opts[:'offset'].nil? && opts[:'offset'] > 10000
|
|
208
|
+
fail ArgumentError, 'invalid value for "opts[:"offset"]" when calling MarketsApi.list_market_browse, must be smaller than or equal to 10000.'
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
if @api_client.config.client_side_validation && !opts[:'offset'].nil? && opts[:'offset'] < 0
|
|
212
|
+
fail ArgumentError, 'invalid value for "opts[:"offset"]" when calling MarketsApi.list_market_browse, must be greater than or equal to 0.'
|
|
213
|
+
end
|
|
214
|
+
|
|
205
215
|
if @api_client.config.client_side_validation && !opts[:'limit'].nil? && opts[:'limit'] > 100
|
|
206
216
|
fail ArgumentError, 'invalid value for "opts[:"limit"]" when calling MarketsApi.list_market_browse, must be smaller than or equal to 100.'
|
|
207
217
|
end
|
|
@@ -223,6 +233,7 @@ module Repull
|
|
|
223
233
|
query_params[:'country'] = opts[:'country'] if !opts[:'country'].nil?
|
|
224
234
|
query_params[:'min_listings'] = opts[:'min_listings'] if !opts[:'min_listings'].nil?
|
|
225
235
|
query_params[:'cursor'] = opts[:'cursor'] if !opts[:'cursor'].nil?
|
|
236
|
+
query_params[:'offset'] = opts[:'offset'] if !opts[:'offset'].nil?
|
|
226
237
|
query_params[:'limit'] = opts[:'limit'] if !opts[:'limit'].nil?
|
|
227
238
|
query_params[:'sort'] = opts[:'sort'] if !opts[:'sort'].nil?
|
|
228
239
|
|
|
@@ -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
|