Webhooks and notifications
Housing Anywhere and Uniplaces can push paid and cancelled bookings to VIVIN through inbound webhooks; VIVIN sends no webhooks back to them.
Before you start
| Item | Value |
|---|---|
| Who it is for | Housing Anywhere and Uniplaces. Every other partner sends bookings with POST /<prefix>/bookings |
| Base URL | https://api.vivin.app. Each webhook is on its partner's Swagger page: /housinganywhere-integration and /uniplaces-integration |
| Listing IDs | Echo the ID from VIVIN's full feed: listingReference for Housing Anywhere, reference_id for Uniplaces (Full listing feeds) |
| Outbound | None. To see results, poll the listing feeds (Tracking results) |
Endpoints
| Method | Path | Auth |
|---|---|---|
POST | /housinganywhere-integration/{landlordKey}/webhook | Authorization: Bearer <partner-token> |
POST | /uniplaces-integration/webhook | x-api-key: <webhook-key> or Authorization: Bearer <partner-token> (Authentication) |
How VIVIN handles a webhook
- VIVIN checks the call at once: credentials, body, required fields, and that the listing belongs to a VIVIN account. A failed check returns an error.
- A paid event queues a booking, created in the background within about a minute, with the same background checks as
POST …/bookings. For example, a stay that overlaps another booking is refused there. - A cancelled event cancels the matching booking at once, as cancelled without refund. VIVIN finds it by your booking ID and the listing reference, so send the same values as on the paid event.
- VIVIN answers
201with a small JSON body (Swagger lists200). Treat any2xxas delivered.
The body may only contain the fields listed for that webhook. Any other field, at the top level or inside the Uniplaces guest object, rejects the whole call with 400.
Housing Anywhere webhook
POST /housinganywhere-integration/{landlordKey}/webhook
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
landlordKey | string | Yes | The landlord's key, or the Integration Email on the landlord's Housing Anywhere card (Settings → Integrations → Booking Platforms). The same key as the full feed |
Request fields
Every value must be a JSON string, as Housing Anywhere sends them. A JSON number returns 400.
| Name | Type | Required | Description |
|---|---|---|---|
notification_type | string | Yes | booking_paid queues a booking. booking_cancelled or booking_canceled cancels it. Letter case is ignored |
listing_external_reference | string | Yes | The listingReference from the Housing Anywhere full feed. The unit must belong to the landlord in the path |
booking_uuid | string | Yes | Stored as the booking's reference. Used to find the booking on cancel and to drop duplicates |
booking_start_date, booking_end_date | string | Paid events | Check-in and check-out, YYYY-MM-DD. A time after a space is ignored |
booking_price | string | Paid events, in practice | First-month rent in cents ("65000" is 650.00), shown as Provider platform payment. Without a value above 0, the booking fails in the background. booking_total is not used, because it includes Housing Anywhere's fee |
tenant_first_name, tenant_last_name | string | No | Cut to 128 characters each. Missing values become Guest and Tenant |
tenant_email | string | No | Matches an existing tenant or creates one. When missing, VIVIN uses a placeholder address that the landlord must replace |
tenant_phone | string | No | Stored on a new tenant |
Housing Anywhere's other fields are accepted and not used: booking_id, booking_total, booking_fee, booking_deposit, booking_currency, booking_tenants_count, booking_advertiser_uuid, booking_external_reference, listing_uuid, listing_alias, listing_price, listing_currency, listing_address, listing_house_number, listing_zip, listing_city, listing_neighborhood, listing_country_code, listing_lat, listing_lng, tenant_birth_date, tenant_gender_code, tenant_nationality and tenant_iso_country_code. VIVIN matches bookings on booking_uuid, not booking_id, and creates a Housing Anywhere booking for one tenant.
Example request
curl -X POST "https://api.vivin.app/housinganywhere-integration/<landlordKey>/webhook" \
-H "Authorization: Bearer <partner-token>" \
-H "Content-Type: application/json" \
-d '{
"notification_type": "booking_paid",
"booking_uuid": "5d0c6f0e-2b1a-4c1e-9d7a-2f3e8c1a9b10",
"booking_start_date": "2026-10-01",
"booking_end_date": "2027-06-30",
"booking_price": "65000",
"booking_currency": "EUR",
"listing_external_reference": "HA-A101",
"tenant_first_name": "Casey",
"tenant_last_name": "Sample",
"tenant_email": "[email protected]",
"tenant_phone": "+15555550100"
}'

Uniplaces webhook
POST /uniplaces-integration/webhook. One URL serves every landlord: VIVIN finds the landlord from the listing reference.
Request fields
| Name | Type | Required | Description |
|---|---|---|---|
event | string | Yes | Hyphens or underscores, any letter case. booking-paid, booking-paid-success and payment-confirmed queue a booking. booking-cancelled, booking-canceled and booking-rejected cancel it. Any other event is acknowledged without action |
offer_api_reference | string or number | No | The reference_id from the Uniplaces full feed, and the preferred way to find the unit. When it is missing, VIVIN uses offer_id. Paid and cancel events need one of the two |
offer_id | string or number | No | Used only when offer_api_reference is missing. It matches only when the landlord linked the unit with that Uniplaces offer number |
booking_id (or booking_Id) | string or number | Yes | Stored as the booking's reference. Used to find the booking on cancel and to drop duplicates |
move_in_date, move_out_date | string | Paid events | Check-in and check-out, YYYY-MM-DD |
contract_price_amount | number | Paid events, in practice | Amount in cents (65000 is 650.00), shown as Provider platform payment. When missing, VIVIN uses booking_total. Without either, the booking fails in the background |
booking_total | number | No | Amount in cents, used only when contract_price_amount is missing |
guest_name or guest.name | string | No | The first word becomes the first name, the rest the last name. Missing values become Guest and Tenant |
guest_email or guest.email | string | No | Matches an existing tenant or creates one. When missing, VIVIN uses a placeholder address that the landlord must replace |
guests_number | number | No | Total number of guests. Guests beyond the first are recorded as extra tenants |
Also accepted and not used: booking_date, rejection_reason, contract_price_currency, admin_fee_amount (a number), admin_fee_currency and accommodation_provider_id. The guest object accepts only name and email.
Example request
curl -X POST "https://api.vivin.app/uniplaces-integration/webhook" \
-H "x-api-key: <webhook-key>" \
-H "Content-Type: application/json" \
-d '{
"event": "booking-paid",
"offer_api_reference": "UP-A101",
"booking_id": 1193557,
"guest_name": "Casey Sample",
"guest_email": "[email protected]",
"guests_number": 1,
"move_in_date": "2026-10-01",
"move_out_date": "2027-06-30",
"contract_price_amount": 65000,
"contract_price_currency": "EUR"
}'
Responses
Both webhooks answer 201 with one of these bodies:
| Body | Meaning |
|---|---|
{ "ok": true } | Booking queued, or booking cancelled |
{ "ok": true, "message": "Booking already recorded" } | A paid event for a booking that exists in VIVIN and is not cancelled. Nothing is queued |
{ "ok": true, "message": "No active booking to cancel" } | A cancel event for a booking VIVIN does not have, has already cancelled, or has not created yet (see Troubleshooting) |
{ "ok": true, "message": "Ignored Uniplaces event: <event>" } | A Uniplaces event VIVIN does not act on |
The reply never says whether the queued booking was created. The landlord sees that in VIVIN.
Errors
Errors use the standard error body:
{
"statusCode": 400,
"message": "Unsupported Housing Anywhere notification_type: booking_requested",
"error": "BadRequestException"
}
| Status | message | Cause | What to do |
|---|---|---|---|
400 | property <name> should not exist | A field the webhook does not accept | Remove it |
400 | <field> must be a string, <field> must be a number conforming to the specified constraints | A value of the wrong JSON type | Send the type listed above |
400 | notification_type must be a string | Housing Anywhere: no notification_type | Send it |
400 | Unsupported Housing Anywhere notification_type: <value> | Housing Anywhere: an event other than paid or cancelled | Do not send other events |
400 | listing_external_reference and booking_uuid are required for booking_paid (or for cancellation) | Housing Anywhere: a missing reference | Send both |
400 | Invalid booking_start_date or booking_end_date | Housing Anywhere: a missing date, or not YYYY-MM-DD | Fix the dates |
400 | landlordKey must be a non-empty value | Housing Anywhere: blank landlordKey in the path | Put the landlord key in the path |
400 | Uniplaces webhook event is required | Uniplaces: no event | Send it |
400 | offer_api_reference (or offer_id) and booking_id are required for paid booking webhooks (or for cancellation webhooks) | Uniplaces: a missing reference | Send both |
400 | Invalid move_in_date or move_out_date for Uniplaces booking | Uniplaces: a missing date, or not YYYY-MM-DD | Fix the dates |
401 | Missing integration credentials and others | A missing or wrong key | See Authentication |
404 | Listing not found for housinganywhere with externalId <id> | The reference is neither a linked unit nor a VIVIN unit ID of the landlord in the path, or landlordKey matches no account | Echo listingReference from that landlord's full feed |
404 | Listing not found for uniplaces with reference <id> | The reference is neither a linked unit nor a VIVIN unit ID | Echo reference_id from the full feed |
409 | Ambiguous uniplaces reference <id>: matches listings on multiple accounts | Two landlord accounts linked the same ID, so VIVIN cannot tell which one you mean | Ask the landlords to fix their unit links |
Retries
- Fix the request before you retry a
4xx. - Retrying a paid event is safe: once the booking exists and is not cancelled, VIVIN answers
Booking already recorded. A repeat that arrives before the first was processed is queued, then dropped as a duplicate without a notification. - A paid event for a booking ID that was imported and then cancelled is dropped: the booking is not created again (Retries and duplicates).
- Webhooks are not rate-limited.
Tracking results
VIVIN does not call your platform back. To check a booking or keep availability in sync, poll the listing feeds:
- One unit, live:
GET /<prefix>/listings/{externalId}. A new booking shows up as a new row inunavailabilities, and a cancelled one disappears. - All units:
GET /<prefix>/listings, rebuilt about every 10 minutes. - Do not rely on the listing's
updatedAt: new bookings and blocks do not change it.
The landlord gets an in-app notification for each booking created or refused, and an email for each refusal (How failures are reported). Nothing is sent to your platform.
Troubleshooting
| Symptom | Likely cause and fix |
|---|---|
No active booking to cancel right after a paid event | The queued booking was not created yet, and it will still be created. Send the cancel again a few minutes later |
404 with your own listing ID | Your ID works only when the landlord linked the unit with it. Echo the ID from VIVIN's full feed |
| The booking was created with a placeholder email | The webhook had no guest or tenant email. The landlord should replace it in the tenant's profile |
| The booking was refused for a missing platform payment | booking_price (Housing Anywhere) or contract_price_amount and booking_total (Uniplaces) were missing or zero |
| Airbnb or Booking.com bookings are missing | They need no webhook. VIVIN collects them after the landlord connects those accounts under Settings → Integrations |
Related
- Creating bookings: the
POST …/bookingsroute for every other partner - Booking lifecycle and validations: the background checks and duplicates
- Full listing feeds: where
listingReferenceandreference_idcome from - Authentication: partner tokens and the Uniplaces webhook key
- Notifications: the landlord's notification history