# Ringing calls

Ring and notify users about calls using the `Call` object.

## Best Practices

- Use unique call IDs for ringing calls (e.g., UUID) - ringing only works once per ID.
- Include the caller in the members list when creating a ring call.
- Use `useCalls()` hook to watch for incoming/outgoing calls.
- Filter calls by `call.isCreatedByMe` to distinguish incoming vs outgoing.
- Call `call.leave({ reject: true })` to reject; `call.join()` to accept.

## Create call

To create a ring call, we need to set the `ring` flag to `true` and provide the list of members we want to call.
It is important to note that the caller should also be included in the list of members.

```typescript {3,5}
const call = client.call("default", crypto.randomUUID());
await call.getOrCreate({
  ring: true,
  video: true,
  data: {
    members: [{ user_id: "myself" }, { user_id: "my friend" }],
  },
});
```

> **Note:**   When using ringing calls, it is recommended to use unique call IDs, as reusing the same call ID may lead to unexpected behavior.

### Call creation options

The following options are supported when creating a call:

| Option     | Description                                                                                                                                                     | Default |
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| `members`  | A list of members to add to this call. You can specify the role and custom data on these members                                                                | -       |
| `custom`   | Any custom data you want to store                                                                                                                               | -       |
| `settings` | You can overwrite certain call settings for this specific call. This overwrites the call type standard settings                                                 | -       |
| `startsAt` | When the call will start. Used for calls scheduled in the future, livestreams, audio rooms etc                                                                  | -       |
| `team`     | Restrict the access to this call to a specific team                                                                                                             | -       |
| `ring`     | If you want the call to ring for each member                                                                                                                    | `false` |
| `notify`   | If you want the call to nofiy each member by sending push notification.                                                                                         | `false` |
| `video`    | When ringing, the notification will indicate whether it’s a video call or an audio-only call, depending on whether you set the video parameter to true or false | -       |

This step will start the signaling flow.
The caller will automatically join the call once the first callee accepts the call.
The call will automatically stop if every callee rejects the call.

## Watch for incoming and outgoing calls

The easiest way to watch for incoming and outgoing calls is to use the `useCalls` hook.

```tsx
import { useCalls, CallingState } from "@stream-io/video-react-sdk";

export const MyCallUI = () => {
  const calls = useCalls();

  // handle incoming ring calls
  const incomingCalls = calls.filter(
    (call) =>
      call.isCreatedByMe === false &&
      call.state.callingState === CallingState.RINGING,
  );

  const [incomingCall] = incomingCalls;
  if (incomingCall) {
    // render the incoming call UI
    return <MyIncomingCallUI call={incomingCall} />;
  }

  // handle outgoing ring calls
  const outgoingCalls = calls.filter(
    (call) =>
      call.isCreatedByMe === true &&
      call.state.callingState === CallingState.RINGING,
  );

  const [outgoingCall] = outgoingCalls;
  if (outgoingCall) {
    // render the outgoing call UI
    return <MyOutgoingCallUI call={outgoingCall} />;
  }

  return null;
};
```

You can also check the sample integration in the following CodeSandboxes:

- [Caller side](https://codesandbox.io/s/stream-video-ringing-caller-x3twcw)
- [Callee side](https://codesandbox.io/s/stream-video-ringing-callee-28wssp)

## Canceling an outgoing call

A caller can cancel an outgoing call until the first callee accepts the call. Canceling a call will stop the signaling flow.

```typescript
await call.leave({ reject: true, reason: "cancel" });
```

Please note that calling `call.leave()` after joining the call won't stop the signaling flow.

## Rejecting an incoming call

A callee can accept or reject an incoming call. To reject the call:

```typescript
await call.leave({ reject: true, reason: "decline" });
```

## Accepting a call

A callee can accept or reject an incoming call. To accept and join the call:

```typescript
await call.join();
```

You can join multiple calls. To allow only one active call, leave joined calls before accepting an incoming call.

## Leave call

To leave a joined call, you can use the `leave` method:

```typescript
await call.leave();
```

## End call

Ending a call requires a [special permission](https://getstream.io/video/docs/react/v2/guides/permissions-and-moderation/). This action terminates the call for everyone.

```typescript
await call.endCall();
```

## Notifying

In some cases, you just want to notify users that you joined a call, instead of ringing.
To do this, you should use the `notify` option:

```typescript
await call.getOrCreate({ notify: true });
```

When notify is true, a regular push notification will be sent to all the members.
This can be useful for livestreams apps or huddles.

Similarly to ringing, you can use the get method if you are sure that the call exists:

```typescript
await call.get({ notify: true });
```

## Ringing individual members

Ring specific members instead of the entire call, or ring members into an existing call using the `ring` method:

```typescript
const call = client.call("default", crypto.randomUUID());
await call.getOrCreate({
  ring: false,
  data: {
    members: [{ user_id: "myself" }, { user_id: "my-friend" }],
  },
});

// note: my-friend needs to be a member of the call
await call.ring({ members_ids: ["my-friend"] });

// to invite a new member and ring them
await call.updateCallMembers({
  update_members: [{ user_id: "my-other-friend" }],
});
await call.ring({ members_ids: ["my-other-friend"] });

// to ring all members
await call.ring();
```

## Keeping track of the ringing state

Track `accepted_by`, `rejected_by`, and `missed_by` states for all rung members. Useful for displaying detailed member status in your UI.

Access this data through the call's `session` state:

```tsx
const { useCallSession } = useCallStateHooks();
const session = useCallSession();
const { accepted_by = {}, rejected_by = {}, missed_by = {} } = session ?? {};

if (accepted_by["sara"]) {
  console.log("sara accepted the call");
}

if (rejected_by["john"]) {
  console.log("john rejected the call");
}

if (missed_by["mary"]) {
  console.log("mary missed the call");
}
```

---

For the most recent version of this documentation, visit [https://getstream.io/video/docs/react/v2/advanced/ringing-calls/](https://getstream.io/video/docs/react/v2/advanced/ringing-calls/).