# Confirmation prompts

Ask for a second click before something destructive with getConfirmation(). Covers its options, replacing the prompt after an answer, building the prompt's buttons yourself, and when a prompt is the wrong tool.

A ban or a wipe should ask before it runs. Written by hand, that's a message with two buttons, a collector that ignores everyone but the caller, a timeout, and a cleanup of the prompt once someone answers.

[`getConfirmation`](https://docs.seedcord.org/packages/gateway/latest/get-confirmation) does all of that in one `await`. It sends a prompt with **Confirm** and **Cancel** buttons and resolves to `true` only when the person who ran the command clicks confirm. A cancel click and a timeout both resolve to `false`.

```ts title="src/handlers/Ban.ts"
import {
    getConfirmation,
    SlashHandler,
    SlashRoute
} from '@seedcord/gateway';

@SlashRoute('ban')
export class Ban extends SlashHandler<'ban'> {
    public async execute(): Promise<void> {
        const target = this.options.getUser('target');

        const confirmed = await getConfirmation(
            this,
            `Ban ${target.username}?`
        );
        if (!confirmed) return;

        await this.event.guild?.members.ban(target.id);
    }
}
```

Pass `this` as the first argument. The prompt uses your handler's own reply surface. That surface picks reply, edit, or follow-up from the interaction's current state.

seedcord ignores a click from anyone else, whether the prompt is ephemeral or public. Nothing answers that click, so Discord shows the other person its own failure message.

## The options

{/* prettier-ignore-start */}

| option         | default              | what it does                                |
| -------------- | -------------------- | ------------------------------------------- |
| `ephemeral`    | `true`               | shows the prompt to the invoking user alone |
| `timeoutMs`    | `30_000`             | how long to wait before resolving `false`   |
| `confirmLabel` | `'Confirm'`          | the confirm button's text                   |
| `cancelLabel`  | `'Cancel'`           | the cancel button's text                    |
| `confirmStyle` | `ButtonStyle.Danger` | the confirm button's color                  |
| `onConfirm`    |                      | replaces the prompt after a confirm click   |
| `onCancel`     |                      | replaces the prompt after a cancel click    |
| `onTimeout`    |                      | replaces the prompt when the wait runs out  |

{/* prettier-ignore-end */}

Only the string form takes the label and style options.

## Replacing the prompt

seedcord deletes the prompt once someone answers or the wait runs out. If it vanishes with nothing in its place, your caller never learns what happened. Set one of the three outcome options to replace the prompt with your reply.

```ts
const status = (text: string) => ({
    components: [new StatusCard(text).component]
});

const confirmed = await getConfirmation(
    this,
    `Ban ${target.username}?`,
    {
        onConfirm: () => status('Banning now.'),
        onTimeout: status('No answer. Nobody was banned.')
    }
);
```

Each one takes a reply or a function returning one. The fence above passes both shapes, a function to `onConfirm` and a plain reply to `onTimeout`. seedcord calls the function after the click, so it reads whatever is true by then.

Without an outcome option, send the result with a fresh [`this.followUp()`](https://docs.seedcord.org/packages/gateway/latest/repliable-handler#follow-up), since a deleted prompt leaves nothing to edit.

## Building the prompt yourself

The string form draws one line of text above **Confirm** and **Cancel**. For a card, an image, or a summary of what's about to change, use the second form. You pass a function, and seedcord hands it the two button ids. Put them on your own buttons and return the whole reply.

```ts
const confirmed = await getConfirmation(this, (ids) => ({
    components: [new GrantRow(ids).component]
}));
```

seedcord's router skips those two ids, so only the prompt's collector gets the click. Use `ids.confirm` and `ids.cancel` as is, since a button carrying any other id never reaches the collector.

Calling `getConfirmation` from a [`ModalHandler`](https://docs.seedcord.org/packages/gateway/latest/modal-handler) fails to compile, since its first parameter accepts every handler kind except a modal one.

> **Gateway only**
>
> `getConfirmation` ships in `@seedcord/gateway` alone. It holds a collector in the running process. An http bot answers each interaction as its own request, with nothing kept between them.

## When a prompt is the wrong tool

The collector runs inside your bot's process. A restart ends every open prompt, and a later click gets Discord's own failure message.

Use a prompt for a decision someone makes in seconds. `timeoutMs` defaults to 30 seconds. Put an approval a moderator might answer hours later on a routed button with a [custom id](/components/custom-ids), which still works after a restart.
