ElefyMove Open API 가이드와 레퍼런스.
이 가이드는 현재 영어로만 제공됩니다.
| 메서드 | 엔드포인트 | 스코프 | 설명 |
|---|---|---|---|
| PUT | /api/public/v1/webhooks | webhooks:manage | webhook 엔드포인트 URL을 설정하고, 선택적으로 이벤트 구독 목록을 교체합니다. |
| GET | /api/public/v1/webhooks | webhooks:manage | 현재 webhook 설정을 조회합니다. 서명 시크릿은 절대 반환되지 않습니다. |
| DELETE | /api/public/v1/webhooks | webhooks:manage | webhook URL을 지우고 전송을 중단합니다. |
/api/public/v1/webhooks/test | webhooks:manage | 현재 구독 여부와 관계없이 설정된 엔드포인트로 서명된 테스트 이벤트를 전송합니다. | |
| GET | /api/public/v1/webhook-deliveries | webhooks:manage | 본인의 webhook 전송 시도를 상태, 시각, 재시도 이력과 함께 나열합니다. |
/api/public/v1/webhook-deliveries/{id}/redeliver | webhooks:manage | 실패했거나 데드레터 처리된 전송을 수동으로 재시도합니다. |
Set your HTTPS endpoint URL either through the API (PUT /webhooks) or from the dashboard’s Webhooks tab; both write the same configuration. 서명 시크릿 회전은 의도적으로 이 API에 포함되어 있지 않습니다 — 반드시 대시보드에서만 진행됩니다. 파트너가 키를 여전히 보유하고 있음을 증명하는 자격 증명을 스스로 회전시킬 수 없도록 하기 위해서입니다.
events on PUT /webhooks is optional and, when sent, replaces your subscription list. Omit it entirely to leave your existing subscription untouched. Send it as an empty array — the same as never setting it — to subscribe to every event; an empty list is not "no events". A non-empty list narrows delivery to exactly those event names. POST /webhooks/test always sends a signed ping, regardless of your subscription.
The delivery log (GET /webhook-deliveries) and manual redelivery (POST /webhook-deliveries/:id/redeliver) are also available through the API, mirroring the dashboard’s delivery log.
| 받을 수 있는 이벤트 | 설명 |
|---|---|
listing.approved | A listing you submitted passed moderation and is live. |
listing.rejected | A listing you submitted was rejected by moderation. |
availability.changed | A listing’s calendar changed outside your own writes — a booking, block, or hold from another channel. |
hold.created | A temporary hold was placed on one of your listings. |
hold.released | A hold was released before it expired. |
hold.expired | A hold reached its TTL and expired. |
booking.created | An ElefyMove booking was confirmed on one of your listings (dates and references only). |
booking.cancelled | An ElefyMove booking on one of your listings was cancelled. |
ping | Manual test delivery — from the dashboard or POST /webhooks/test — same signing, no side effects. |
Every delivery is a JSON POST carrying three headers: X-Elefy-Event, X-Elefy-Timestamp, and X-Elefy-Signature. The signature is hex(HMAC-SHA256(webhookSecret, timestamp + "." + rawBody)) — recompute it over the exact bytes you received and compare in constant time:
import { createHmac, timingSafeEqual } from "node:crypto";
import express from "express";
const app = express();
// Capture the RAW request bytes — a re-serialized JSON.stringify(body)
// may not byte-match what was signed.
app.post(
"/webhooks/elefymove",
express.raw({ type: "application/json" }),
(req, res) => {
const signature = req.header("X-Elefy-Signature") ?? "";
const timestamp = req.header("X-Elefy-Timestamp") ?? "";
const rawBody = req.body.toString("utf8");
const expected = createHmac("sha256", process.env.ELEFY_WEBHOOK_SECRET)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
const valid =
signature.length === expected.length &&
timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
if (!valid) return res.status(401).end();
// Optional hardening: reject timestamps older than a few minutes
// to close the replay window.
const event = JSON.parse(rawBody);
console.log(event.event, event.data);
// Acknowledge fast (2xx) — do heavy work asynchronously.
res.status(200).end();
},
);Use “Send test event” in the dashboard, or call POST /webhooks/test directly, to enqueue a signed ping delivery to your endpoint. Either way it goes through the exact same signing and retry pipeline as production events, with no side effects — the right way to verify your handler end to end. The response is 202 Accepted: queued for the next delivery cron run, not delivered synchronously.