Browse the docs

Events

Read back every event Moon generated, delivered or not.

Every event Moon generates for your organization is stored and readable, whether or not its webhook delivery succeeded. If your endpoint was unreachable, this is how you catch up.

The recovery path

A delivery that fails is retried for about 46 hours (see Webhooks). If your endpoint was down longer than that, or you want to confirm nothing was missed, read the events back:

cURL

curl --request GET \
     --url 'https://api.themooncard.com/v2/api-gateway/events?start_date=2026-08-16&status=failed' \
     --header 'accept: application/json' \
     --header 'x-api-key: YOUR_API_KEY'

Each event carries the same type and data the webhook POST would have carried, so you can hand data to the same handler that consumes live deliveries and get the same result. The event's id is the webhook_event_id in the delivered body, which is what lets you tell a replay apart from something you already processed.

What an event looks like

JSON

{
  "events": [
    {
      "id": "9f8b7a6c-5d4e-4f3a-8b2c-1d0e9f8a7b6c",
      "type": "CARD_TRANSACTION",
      "created_at": "2026-08-17T12:00:00.000Z",
      "delivery": {
        "status": "delivered",
        "attempts": 1,
        "max_attempts": 9,
        "last_attempt_at": "2026-08-17T12:00:01.000Z",
        "next_attempt_at": null,
        "delivered_at": "2026-08-17T12:00:01.000Z",
        "response_status_code": 200
      },
      "data": { }
    }
  ],
  "pagination": { }
}

The delivery object answers two different questions:

  • Did it arrive? status is delivered, failed, or pending, and response_status_code is what your endpoint answered on the attempt being described — null when no reply arrived at all, which is a different situation from a 500 and worth distinguishing when you open a support request.
  • Is anything still coming? next_attempt_at alone tells you: a timestamp means another attempt is due then, null means the event is settled and nothing further will be sent. You do not need to know the retry schedule to read it.

attempts counts the attempts actually made, and max_attempts is the ceiling for this delivery.

Filters

ParameterValues
statuspending, delivered, failed
start_date, end_dateA calendar day (2026-08-16) or a full instant with an explicit offset (2026-08-16T09:15:00Z)
current_page, per_pageStandard pagination; up to 100 per page

Filtering by a type outside that list returns an empty page rather than an error. The list grows as new event types are added, so read it as the set that exists today rather than a fixed enum — see Webhooks for what each one means.

To fetch one event you already have the id for, use GET /events/{event_id}. An id that does not exist, or that belongs to another organization, returns a 404.

Working out what you missed

The practical shape of a catch-up, after an outage on your side:

  1. List with status=failed and a start_date covering the outage.
  2. Page through with per_page=100, ordering by created_at as returned.
  3. Feed each data to your normal handler, keyed on the event id so a replay of something you did process is a no-op.
  4. Re-run the same query afterwards — anything still pending has attempts left and will arrive on its own.

Events remain readable after the endpoint that produced them is deleted or replaced, so changing your webhook URL does not cost you the history.

  • Webhooks — signature verification, the retry schedule and the delivery contract.
  • Pagination — page parameters and the pagination object.
  • Data formats and ids — timestamp and identifier formats.

Last updated October 22, 2026