> ## Documentation Index
> Fetch the complete documentation index at: https://vlyai-1c28d863.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Actions

> Convex actions — for side effects, third-party API calls, and anything that touches the outside world.

Actions can call third-party APIs, use `process.env`, run for up to 10 minutes, and orchestrate other Convex functions. They're **not transactional** — for atomicity, do data writes inside mutations called from the action.

## Anatomy

```typescript convex/notifications.ts theme={null}
import { action } from "./_generated/server";
import { v } from "convex/values";
import { api } from "./_generated/api";

export const sendWelcomeEmail = action({
  args: { userId: v.id("users") },
  handler: async (ctx, { userId }) => {
    const user = await ctx.runQuery(api.users.get, { id: userId });
    if (!user) return;

    await fetch("https://api.resend.com/emails", {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${process.env.RESEND_API_KEY}`,
        "Content-Type":  "application/json",
      },
      body: JSON.stringify({
        from: "hello@yourapp.com",
        to: user.email,
        subject: "Welcome",
        html: `<p>Hi ${user.name}, welcome.</p>`,
      }),
    });

    await ctx.runMutation(api.users.markWelcomed, { id: userId });
  },
});
```

## ctx.run\* helpers

Inside an action, call other Convex functions:

```typescript theme={null}
const user   = await ctx.runQuery(api.users.get, { id });
const result = await ctx.runMutation(api.users.update, { id, ... });
const data   = await ctx.runAction(api.other.someAction, { ... });
```

## On the client

```typescript theme={null}
import { useAction } from "convex/react";
const send = useAction(api.notifications.sendWelcomeEmail);
await send({ userId });
```

## When to pick action vs mutation

| Need | Function type |
| - | - |
| Write to the DB only | Mutation |
| Read from the DB only | Query |
| Call a third-party API | Action |
| Use `process.env` | Action |
| Long-running work (>10s) | Action |

## Limits

* **10-minute runtime** per invocation.
* **Not transactional**: a failure mid-action leaves the world in whatever partial state was reached.
* **No reactive subscriptions** — clients call actions, but actions don't push back.

## Tips

<Tip>
  **Wrap third-party calls in try/catch.** External APIs fail; handle the failure gracefully.
</Tip>

<Tip>
  **For idempotency, store a key in the DB.** Before calling Stripe / Resend / etc., check whether you've already done this work.
</Tip>

## Related

<CardGroup cols={3}>
  <Card title="Mutations" icon="pencil" href="/convex/mutations">
    For DB writes called from actions.
  </Card>

  <Card title="Queries" icon="search" href="/convex/queries">
    For DB reads called from actions.
  </Card>

  <Card title="Background jobs" icon="cog" href="/features/data/background-jobs">
    Long-running patterns.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.