SSeev PlusDocs
Developer Dashboard

Developer Webhooks

Configure webhook endpoints and inspect delivery logs for Seev API events.

API product

Requires developer access and an API key

Developer webhooks let your application receive real-time events from Seev API products. Use them to fulfil orders, update internal records, notify customers, or reconcile transactions without polling.

If you are new to webhooks

A webhook is a notification from Seev to your server. Instead of repeatedly asking whether a payment succeeded, your server exposes one HTTPS URL and Seev sends the result there.

You need webhooks when payment completion must trigger work reliably, such as releasing an order or granting access. A browser redirect is useful for the customer experience, but it should not be the only proof your server trusts.

The minimum safe setup is:

  1. Create one sandbox endpoint.
  2. Store the signing secret when it is shown.
  3. Read the raw request body.
  4. Verify the timestamp and signature.
  5. Ignore an event ID that was already processed.
  6. Apply your business change.
  7. Return a 2xx response quickly.
  8. Review the delivery in Webhook logs.

How webhooks work

Your system triggers a Seev API event
  -> Seev sends a POST request to your webhook endpoint
  -> Your webhook handles the event and returns a response to Seev
  -> Seev saves the successful delivery or retries depending on your response
  1. You create a webhook endpoint in the Developer Dashboard.
  2. Your system performs an API action that triggers a Seev event.
  3. Seev sends a POST request with the event payload to your endpoint URL.
  4. Your webhook verifies and processes the event, then returns a response to Seev.
  5. Seev records the delivery as successful when it receives a 2xx response, or marks it for retry when the response fails or times out.

Webhook endpoints

Create a webhook endpoint from Seev API -> Webhooks.

You will need:

FieldDescription
Endpoint URLA publicly reachable HTTPS URL that receives Seev webhook events.
EventsThe event types you want this endpoint to receive.

Example endpoint URL:

https://api.example.com/webhooks/seev

Your endpoint must be publicly reachable over HTTPS. For local development, use a tunnelling tool like ngrok or Cloudflare Tunnel.

Start with both payment events unless your application genuinely needs only one. A success handler updates fulfilled work, while a failure handler can keep the order unpaid and let the customer retry.

Event types

Seev API webhooks currently support these events:

EventDescription
payment.succeededA checkout payment completed successfully.
payment.failedA checkout payment failed or was declined.

Webhook signing

When you create a webhook endpoint, Seev returns a signingSecret once:

{
  "id": "webhook_id",
  "url": "https://api.example.com/webhooks/seev",
  "events": ["payment.succeeded"],
  "status": "active",
  "signingSecret": "whsec_..."
}

Store this secret securely. It is used to verify that webhook requests were sent by Seev and that the payload was not modified.

Every webhook request includes these headers:

HeaderDescription
X-Seev-Event-IDUnique delivery event ID. Use this for idempotency.
X-Seev-Event-TypeEvent name, for example payment.succeeded.
X-Seev-TimestampUnix timestamp used in signature generation.
X-Seev-SignatureHMAC signature in the format v1=<hex_digest>.

Seev signs the raw request body using:

HMAC_SHA256(signingSecret, timestamp + "." + rawBody)

The resulting hex digest is sent as:

X-Seev-Signature: v1=<digest>

Verifying signatures

Always verify the signature before processing a webhook.

Important:

  • Use the raw request body, not parsed JSON.
  • Reject old timestamps, for example older than 5 minutes.
  • Compare signatures using a constant-time comparison.
  • Store X-Seev-Event-ID before applying side effects so retries do not double-process the event.

Example Node/TypeScript verification:

import crypto from "crypto";

function verifySeevWebhook({
  rawBody,
  timestamp,
  signature,
  secret,
}: {
  rawBody: string;
  timestamp: string;
  signature: string;
  secret: string;
}) {
  const age = Math.abs(Date.now() / 1000 - Number(timestamp));
  if (!timestamp || Number.isNaN(Number(timestamp)) || age > 300) {
    return false;
  }

  const expected =
    "v1=" +
    crypto
      .createHmac("sha256", secret)
      .update(`${timestamp}.${rawBody}`)
      .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature || "")
  );
}

Example handler:

export async function POST(req: Request) {
  const rawBody = await req.text();

  const eventId = req.headers.get("X-Seev-Event-ID");
  const eventType = req.headers.get("X-Seev-Event-Type");
  const timestamp = req.headers.get("X-Seev-Timestamp");
  const signature = req.headers.get("X-Seev-Signature");

  const valid = verifySeevWebhook({
    rawBody,
    timestamp: timestamp || "",
    signature: signature || "",
    secret: process.env.SEEV_WEBHOOK_SECRET!,
  });

  if (!valid) {
    return new Response("Invalid signature", { status: 401 });
  }

  const event = JSON.parse(rawBody);

  // Idempotency: if eventId was already processed, return 2xx.
  // Then handle eventType/payment data safely.

  return Response.json({ received: true });
}

Webhook logs

The Webhook logs tab helps you inspect delivery attempts.

FieldDescription
URLThe endpoint path that received the event.
Response timeHow long your endpoint took to respond.
HTTP statusThe HTTP status code returned by your server.
Event typeThe Seev event name.
StatusWhether the delivery completed or failed.
DateWhen the delivery attempt happened.

Use logs to debug failed deliveries, slow endpoints, or unexpected status codes.

Handling events

Your endpoint should:

  1. Accept POST requests from Seev.
  2. Verify the webhook signature using the raw request body.
  3. Process the event idempotently.
  4. Return a 2xx response quickly.

Always make webhook handlers idempotent. The same event may be delivered more than once, especially when Seev retries after a timeout or non-2xx response.

Example handler shape:

export async function POST(req: Request) {
  const event = await req.json();

  // Store the event ID or transaction reference before taking action.
  // If you have already processed it, return a 2xx response.

  return Response.json({ received: true });
}

Retries and delivery

A delivery is marked successful when your endpoint returns any 2xx response. Non-2xx responses, connection failures, or timeouts are marked as failed in Webhook logs.

You can manually retry any webhook delivery from the dashboard, including successful deliveries. A retry creates a new delivery log with the same payload and a new event ID.

Best practices

  • Respond quickly. Return a 2xx response as soon as you safely can, then process slower work asynchronously.
  • Make handlers idempotent. Store a unique event ID or transaction reference before applying side effects.
  • Verify signatures. Do not trust webhook payloads until signature verification is available and passing.
  • Do not trust redirects alone. For payment fulfilment, rely on server-side verification and webhook delivery instead of only the customer's browser redirect.
  • Log raw events. Keep enough event data to debug delivery issues and reconcile transactions later.

On this page