Browse the docs

Create webhook

POST /v2/api-gateway/webhooks

Registers the webhook URL and returns the signing secret used to verify delivery signatures. The secret appears ONLY in this response and in the rotate response — store it now, there is no endpoint that reads it back. The URL must be a publicly reachable http(s) endpoint and is probed with a POST (10 s timeout); a network error or 5xx reply is rejected. One webhook per organization: any previously registered URL is replaced. Same contract as V1 POST /webhook.

Registers the URL that receives your webhook deliveries. You may have one active webhook at a time — registering again replaces the previous one.

Response

The 201 response includes the signing secret for this webhook:

JSON

{
  "message": "Webhook created successfully",
  "signing_secret": "whsec_4f8c2a1e9b7d3f6a0c5e8b2d7f1a4c9e6b3d8f0a2c5"
}

signing_secret is returned only here and from the rotate endpoint. There is no endpoint that reads it back, so store it when you receive it. If you lose it, call POST /v2/api-gateway/webhooks/signing-secret/rotate for a new one.

Use it to verify the Moon-Signature header on every delivery — see Verifying Webhook Signatures.

  • GET /v2/api-gateway/webhooks returns the registered URL. It never returns the signing secret.
  • DELETE /v2/api-gateway/webhooks removes the registration.

Requirements for the URL

  • Publicly reachable over HTTPS.
  • Must answer our registration check without a 5xx. Private, loopback and link-local addresses are rejected.
  • Return 200 from your handler on delivery, or we retry three times with 5s / 10s / 20s backoff.

Request

Authentication: your API key in the x-api-key header.

Headers

FieldTypeDescription
Idempotency-KeystringA unique string you choose, up to 255 characters, that makes this request safe to retry. If a request times out or fails in transit, send it again with the same key: the status code and body of the first attempt are returned and the operation is not performed a second time. Stored replies — including failures — are replayed for 24 hours, after which the same key starts a fresh request. Reusing a key for a different request, or sending it while the first request is still running, returns 409. Omit the header and the request behaves exactly as before. Document upload endpoints do not accept it.

Body

FieldTypeDescription
url requiredstring, uriAbsolute http/https URL that will receive webhook POSTs. Must resolve to a public host (no private/reserved IPs, no embedded credentials); it is probed with a POST on registration and must not answer with a network error or 5xx.

Example request

cURL

curl --request POST \
     --url 'https://api.themooncard.com/v2/api-gateway/webhooks' \
     --header 'x-api-key: YOUR_API_KEY' \
     --header 'content-type: application/json' \
     --data '{
       "url": "https://example.com/moon/webhooks"
     }'

Responses

201 Success
FieldTypeDescription
message requiredstring
signing_secret requiredstringHMAC signing secret for verifying webhook payloads. Shown only on create/rotate. Always 49 characters: the whsec_ prefix plus 43 base64url characters.

JSON

{
  "message": "Webhook created successfully",
  "signing_secret": "whsec_7Jd2Kq9Xr4Tn6Vb1Zc8Ye3Aw5Sh0Pl2Mg7Uf4Jx6Rk9"
}
400 Error

Validation failed (errors[]), or { message, code } with WEBHOOK_URL_NOT_ALLOWED (not a public http(s) URL) / ERROR_SENDING_POST_REQUEST (the URL did not answer the probe with a non-5xx status).

The body is the standard error object: see Errors.

401 Error

Missing or invalid credentials, e.g. { "message": "Invalid API Key", "code": "UNAUTHORIZED" }.

The body is the standard error object: see Errors.

409 Error

The Idempotency-Key you sent is already in use. IDEMPOTENCY_KEY_REUSED — the key was used for a different request; send a new key, or repeat the original request exactly to receive its stored response. IDEMPOTENCY_KEY_IN_PROGRESS — the first request with this key has not finished yet; retry in a few seconds.

The body is the standard error object: see Errors.

500 Error

Unexpected server error. Body is { message: "Internal server error", code: "INTERNAL_SERVER_ERROR" }.

The body is the standard error object: see Errors.

Last updated September 4, 2026