# Approvals

Part of the [Ownbox SDK reference](https://www.ownbox.io/sdk/reference.md).

## m.propose

```python
m.propose(kind, *, title, detail=None)
```

Hold an action until a person decides.

The owner sees it on Approvals, and a push on their phone. When they say yes, your Ownbox runs what `m.on_approve(kind, fn)` registered, once, with `detail`. The same kind and detail while one waits is the same proposal. Never raises.

**Needs in machine.yaml:** Nothing

**Returns:** `{"status": "waiting" | "repeat" | "refused", "id", "code", "reason", "href"}`. Decide on `code`: "no_such_kind" (register it with `m.on_approve` first), "bad_kind", "too_large" (detail over 16,000 characters as JSON), "bad_title".

Example (inside a job):

```python
asked = m.propose("send_quote", title="Email the quote to Ava", detail={"quote": 41})
```

## m.on_approve

```python
m.on_approve(kind, fn)
```

What runs when a person approves a proposal.

`fn(detail)` runs once, after they said yes. `kind` is lowercase letters, digits and underscores; register it before the machine proposes one.

**Needs in machine.yaml:** Nothing

Example (where the machine is defined):

```python
def send_quote(detail):
    pid = m.person("email", "ava@example.com")
    return m.send_email(pid, {"subject": "Your quote", "text": "Here it is."}, key=f"quote:{detail['quote']}")

m.on_approve("send_quote", send_quote)
```

