elefymove

开发者文档

ElefyMove Open API 的指南与参考。

这些指南目前仅提供英文版。

Endpoints

方法端点权限范围用途
PUT/api/public/v1/webhookswebhooks:manage设置你的 webhook 端点 URL,并可选择替换事件订阅列表。
GET/api/public/v1/webhookswebhooks:manage读取你当前的 webhook 配置。永远不会返回签名密钥。
DELETE/api/public/v1/webhookswebhooks:manage清除你的 webhook URL 并停止投递。
POST/api/public/v1/webhooks/testwebhooks:manage无论当前订阅了哪些事件,都向已配置的端点发送一次已签名的测试事件。
GET/api/public/v1/webhook-deliverieswebhooks:manage列出你自己的 webhook 投递尝试记录,包括状态、时间戳和重试历史。
POST/api/public/v1/webhook-deliveries/{id}/redeliverwebhooks:manage手动重试一次失败或已进入死信状态的投递。

Configuration

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.

Events

可接收的事件用途
listing.approvedA listing you submitted passed moderation and is live.
listing.rejectedA listing you submitted was rejected by moderation.
availability.changedA listing’s calendar changed outside your own writes — a booking, block, or hold from another channel.
hold.createdA temporary hold was placed on one of your listings.
hold.releasedA hold was released before it expired.
hold.expiredA hold reached its TTL and expired.
booking.createdAn ElefyMove booking was confirmed on one of your listings (dates and references only).
booking.cancelledAn ElefyMove booking on one of your listings was cancelled.
pingManual test delivery — from the dashboard or POST /webhooks/test — same signing, no side effects.

Verifying signatures

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();
  },
);

Retries & redelivery

  • Respond with a 2xx quickly — anything else counts as a failed attempt.
  • Failed deliveries retry on a backoff of 1m, 5m, 30m, 2h, 12h, then dead-letter.
  • Failed and dead-lettered deliveries can be redelivered manually from the dashboard’s delivery log.
  • Deliveries can arrive more than once — key your processing on the delivery id or your own idempotency check.

Test deliveries

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.