# Elements events and errors

> Every event Elements send to your page, what each one carries, and the one error shape with stable codes.

Source: https://shopfa.st/docs/elements/events

```js
elements.on("error", (e) => console.error(e.code, e.message));
elements.on("complete", (e) => location.assign(`/thanks?order=${e.order.number}`));
elements.on("*", (data, name) => console.debug(name, data)); // everything, while you build
```

`on` returns a function that stops listening. Each element has its own `on` for the events that come from it.

## Events

| Event | When | Data |
| --- | --- | --- |
| `ready` | An element loaded and can be used, and once when the cart is ready | `{ element, store }`: the element type, or `null` with `store: { name, currency, testMode }` |
| `change` | The buyer changed something | `{ element, kind, value, complete, empty }` |
| `cart` | The cart changed: lines, quantities, codes, totals | `{ count, currency, lines, subtotalMinor, discountMinor, taxMinor, totalMinor, taxIncluded, codes }`. `taxIncluded` is `true` when the store's prices include tax: `taxMinor` is then inside `totalMinor`, not added to it |
| `waiver` | The EU and UK immediate delivery box showed, hid, or became required | `{ shown, required, country }` |
| `error` | Anything went wrong, anywhere | The [error shape](#errors) |
| `resize` | An element changed size (the script already resizes its frame) | `{ element, height, width }` |
| `focus`, `blur` | An element took or lost focus | `{ element }` |
| `navigate` | The buyer is handed to a gateway that needs its own window | `{ url, mode, method }`: `url` is the gateway's address, `mode` `popup` or `redirect` |
| `complete` | The order is paid | `{ order: { checkoutId, orderId, number, url, totalMinor, currency, test } }` |
| `trace` | Diagnostics: refused brand rules, missing elements, contrast warnings | `{ level, source, code, message, element }` |
| `loaderror` | An element's frame did not load at all | `{ element, reason }`: `timeout`, `error` or `origin_not_allowed` |

Money is always in minor units (cents) of the store's currency: `totalMinor: 2400` is $24.00.

### What `change` tells you

`kind` is `email`, `quantity`, `method`, `country`, `consent`, `marketing`, `waiver`, `field`, `code`, `tip`, `variant`,
`offer` or `outcome`. Your page never gets what the buyer typed: for the email and their details you get `complete`
and `empty` only. For a way to pay, a country, a tip or a product option you get the value (`"sandbox:card"`,
`"DE"`, `"p:10"`, the option id).

### The order link

`complete` carries the order page's address. It shows the order's status to anyone; keys and downloads show once
the buyer opens it from their receipt email or from **View your order** in the element, which carries the order's
access in the store's own frame. Your page never holds it.

## Errors

Everything that can fail arrives in `error`, in one shape:

```js
elements.on("error", (e) => {
  e.type;        // "load" | "session" | "validation" | "order" | "payment"
  e.code;        // stable, see below
  e.message;     // for the buyer, may change
  e.element;     // the element to look at, or null
  e.field;       // the field, like "email" or "custom:discord_username", or null
  e.recoverable; // true when the buyer can fix it and try again
});
```

Handle `code`. "Out of stock" wants a different answer from "card declined".

| Code | Type | What happened |
| --- | --- | --- |
| `origin_not_allowed` | load | Your store has not allowed this website. Add it under [allowed websites](https://shopfa.st/docs/elements/security#allowed-websites). |
| `load_failed` | load | A frame did not load. |
| `store_unavailable` | session | The store is closed, in maintenance or suspended. |
| `network_error` | session | The buyer's connection dropped. |
| `session_expired` | session | The cart ended (after a long idle time). Reload the page. |
| `product_not_found` | validation | An item is not for sale at this store. |
| `out_of_stock` | validation | Sold out, or fewer left than asked for. |
| `cart_empty`, `cart_full` | validation | Nothing to pay for, or too many different items. |
| `quantity_limit` | validation | Over the most per order. |
| `coupon_invalid`, `gift_card_invalid` | validation | The code does not exist or does not apply. |
| `email_invalid` | validation | Not an email address. |
| `email_rejected` | validation | The store refused the email (a disposable domain, for example). |
| `field_required`, `field_invalid` | validation | A detail or a question needs an answer; `field` says which. |
| `consent_required` | validation | Your terms are not accepted. |
| `waiver_required` | validation | A buyer in the EU, the EEA or the UK has not asked for immediate delivery. |
| `email_verification_required` | validation | Fraud Shield sent the buyer a 6-digit code; the email element shows the box. |
| `verification_code_invalid` | validation | Wrong or expired code. |
| `element_missing` | validation | Your store asks for something no mounted element shows. |
| `sanctions_blocked` | order | Sanctions do not allow sales to the buyer's country or region. Not recoverable. |
| `checkout_blocked` | order | Fraud Shield blocked the checkout. Not recoverable. |
| `rate_limited` | order | Too many tries in a short time. |
| `checkout_expired` | order | The payment took too long. Try again. |
| `order_locked` | order | A payment is in progress; call `elements.edit()` to change the cart. |
| `method_unavailable` | payment | That way to pay does not fit this country or total. |
| `payments_not_set_up` | payment | The store cannot take payments yet. |
| `payment_declined` | payment | The card or account was declined. |
| `payment_failed` | payment | The payment provider failed or is down. |
| `payment_window_blocked` | payment | The browser blocked the payment window; the payment element offers to open it. |
| `payment_cancelled` | payment | The buyer closed the payment window or went back. |
| `unknown` | any | Something else. `message` says what. |

New codes may be added. Treat a code you do not know like `unknown`.
