inquiry.created

A guest asked about dates before booking, and the inquiry is waiting on you.

When it fires

Fires once per inquiry, when it reaches Repull. data.object is the inquiry exactly as GET /v1/inquiries returns it, so you can answer straight from the payload: pre-approve with POST /v1/conversations/{conversationId}/pre-approval, or send your own terms with /special-offers. Inquiries relayed by a property management system carry relayedBy; answer those in that system.

Payload

Every delivery uses the same outer envelope (event, eventId, apiVersion, timestamp, data). Dedupe on eventId — it stays stable across retries and replays, while the X-Repull-Delivery-Id header changes on every attempt.

{
  "event": "inquiry.created",
  "eventId": "3f1c9a2e-8b7d-4c6a-9e0f-1a2b3c4d5e6f",
  "apiVersion": "2026-04",
  "timestamp": "2026-05-01T12:34:56.000Z",
  "data": {
    "object": {
      "id": "25173",
      "conversationId": "164743",
      "listingId": "23892",
      "customerId": "1",
      "channel": "airbnb",
      "status": "open",
      "checkIn": "2026-10-23",
      "checkOut": "2026-11-11",
      "guests": {
        "total": 2,
        "adults": 2,
        "children": 0,
        "infants": 0,
        "pets": 0
      },
      "expectedPayout": {
        "amount": 2152.6,
        "currency": "USD"
      },
      "reservationId": null,
      "relayedBy": null,
      "respondBy": "2026-09-23T17:40:38.725Z",
      "respondedAt": null,
      "createdAt": "2026-09-22T17:40:39.000Z",
      "updatedAt": "2026-09-22T17:40:39.000Z"
    },
    "occurredAt": "2026-09-22T17:40:39.000Z",
    "revision": "2026-09-22T17:40:39.000Z"
  }
}

Verifying signatures

Every delivery includes a timestamped X-Repull-Signature header of the form t=<unix_ts>,v1=<hex>, where v1 is HMAC-SHA256(signing_secret, `${t}.${raw_body}`). Verify it before processing — see Verify Signatures for full Node.js and Python examples.

Use the raw body

Sign the raw request body exactly as received, not a re-stringified JSON object. Re-serialisation can reorder keys or change whitespace and break the signature.

Example handler

app.post('/webhooks/repull', express.raw({ type: 'application/json' }), async (req, res) => {
  if (!verifyRepullSignature(req)) return res.sendStatus(401)
  const { event, data } = JSON.parse(req.body.toString())
  res.sendStatus(200)

  if (event === 'inquiry.created' && !data.object.relayedBy) {
    const inq = data.object
    await fetch(`https://api.repull.dev/v1/conversations/${inq.conversationId}/pre-approval`, {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.REPULL_API_KEY}`,
        'Idempotency-Key': `preapprove-${inq.id}`, // a redelivery cannot pre-approve twice
      },
    })
  }
})

Common patterns

  • Answer before respondBy: Airbnb counts it toward your response rate.
  • Build the Idempotency-Key from the inquiry id, so a redelivered webhook cannot send a second pre-approval or offer.
  • An inquiry whose time simply runs out, with no update from Airbnb, fires no event. GET /v1/inquiries still reports it as expired.

Tip: Acknowledge with a 2xx status within 10 seconds. Failed deliveries are retried up to 5 times with exponential backoff.Webhook reliability →

AI