# Connect an Apple Account and Check Each Service

Canonical: https://figment.so/blog/connect-apple-account-first-time

Connecting an Apple Account to Figment is one step. Getting each service into a **ready** state is not. iMessage, Contacts, Calendar, and Reminders each have their own Apple-side approval, sync, and Mac permission sequence. Check each service's state before your app makes requests against it—a signed-in account does not automatically mean a ready service. For the developer overview, see [OAuth for iCloud](/oauth-for-icloud).

## Service readiness states

Figment tracks a state for every service on a connection. The state appears in the `connection.services` map returned by `GET /v1/connections/{connection_id}`.

| State | Meaning |
|---|---|
| `connecting` | Initial setup in progress |
| `needs_approval` | A user action is required before this service can proceed |
| `syncing` | The service is active but local data is still downloading |
| `ready` | The service is available for requests within your granted scopes |
| `offline` | The Mac worker has lost contact; most cases recover automatically |
| `reconnect_required` | The user must re-authorize part of the connection |
| `revoked` | The user removed access; will not recover without a new grant |

Non-ready services reject operations. A service in `syncing` is not yet `ready`—reads will fail. Check state at the start of each session, not only at connection time.

## Connect your Apple Account

[Register your app](/apple-connect/developers) first to get a `client_id` and to set your exact HTTPS redirect URI. The sandbox is free; a live connection is $29/month per active Apple connection, and access starts after setup.

**OAuth flow:**

1. Build an authorization URL to `https://figment.so/apple-connect/authorize`. Include `client_id`, your exact `redirect_uri`, `response_type=code`, the scopes you need, a `state` value, and a fresh PKCE `code_challenge` with `code_challenge_method=S256`.

2. Redirect the user to that URL. Figment's hosted screen signs the user into Figment and presents the app-consent step, where the user selects an Apple Account connection and approves the requested scopes. Apple sign-in and trusted-device approval on the Mac are part of connection setup and happen before the OAuth grant is issued. All codes and tokens are issued by Figment, not Apple.

3. Figment redirects to your `redirect_uri` with `code` and `state`. Verify `state` matches before continuing.

4. Exchange the code at `POST https://figment.so/api/apple-connect/oauth/token` with `grant_type=authorization_code`, `client_id`, `redirect_uri`, `code`, and `code_verifier` as `application/x-www-form-urlencoded`.

5. The response includes `access_token`, `refresh_token`, `expires_in`, `scope`, and `connection_id`. Store the `connection_id`—it identifies this Apple connection in every subsequent API call. Access tokens expire after 900 seconds; refresh using `grant_type=refresh_token` with `client_id` and `refresh_token`, and store the rotated refresh token. Your app never receives the Apple password.

## First-connection checklist

The table covers the services with a public customer endpoint. After completing the OAuth flow, confirm each service your app depends on reaches `ready` before making data requests.

| Service | Availability | Apple-side requirement | First-time note |
|---|---|---|---|
| **iMessage** | Live — requires account setup and approval; live access depends on capacity | Trusted-device approval; Messages in iCloud enabled on iPhone and Mac | History can be incomplete even when `ready`; check `historyComplete` on list responses ([Apple guide](https://support.apple.com/en-us/102545)) |
| **SMS / MMS / RCS** | Live — same connection as iMessage | iPhone must be on, online, and signed into the same Apple Account | Messages in iCloud includes SMS, MMS, and RCS automatically; a separate forwarding switch is not required when Messages in iCloud is enabled ([Apple guide](https://support.apple.com/en-us/102545)) |
| **Contacts** | Synthetic sandbox only — live access unavailable | — | Sandbox returns invented data; every response includes `"scope": "synthetic sandbox data"` |
| **Calendar** | Synthetic sandbox only — live access unavailable | Supply both `start` and `end` ISO timestamps; range must not exceed 366 days | Sandbox calendar items are synthetic; `end` must follow `start` |
| **Reminders** | Synthetic sandbox only — live access unavailable | — | `completed` defaults to `false`; pass `completed=true` to include completed items |

Other Apple services—Mail, Photos, iCloud Drive, Notes, Keychain, Safari, Voice Memos, Find My, Home, Shortcuts, and Books—sync locally on the connected Mac but have no public Figment customer endpoint. Figment does not currently expose a customer API for them.

## Check status with the API

After the OAuth exchange you have a `connection_id`. Fetch the connection to read per-service state:

```http
GET https://figment.so/api/apple-connect/v1/connections/con_...
Authorization: Bearer ACCESS_TOKEN
```

Each entry in `connection.services` is an object with `state`, `reason`, and `observedAt` (epoch milliseconds). Only services on the granted connection appear:

```json
{
  "connection": {
    "id": "con_...",
    "mode": "sandbox",
    "services": {
      "messages": {
        "state": "ready",
        "reason": null,
        "observedAt": 1731369600000
      },
      "contacts": {
        "state": "syncing",
        "reason": null,
        "observedAt": 1731369590000
      }
    }
  }
}
```

Only proceed with service-specific operations once that service shows `ready`. For iMessage, also check `historyComplete` on list responses—native history can still be downloading after the service reaches `ready`. A `ready` state does not guarantee delivery of outbound messages.

## If a service shows offline or reconnect_required

`offline` usually means the Mac has temporarily lost contact. Most cases resolve automatically; if the state persists, confirm the Mac is on and connected to the network.

`reconnect_required` means the user must re-authorize part of the connection—typically because a trusted-device session expired or a system permission was revoked. Send the user back through the authorization flow to restore it. For Mac system permissions (Full Disk Access, Automation, Contacts, Calendars), see [Grant the Mac Permissions Your Connector Needs](/blog/mac-connector-permissions). For iMessage history that is incomplete after recovery, see [Fix Missing iMessage History on a Connected Mac](/blog/imessage-history-not-syncing).

---

[Register your app and start in the free sandbox](/apple-connect/developers). Each active live Apple connection is $29/month—access starts after setup. Manage grants and revocations at [your account page](/apple-connect/account). For safe sending and idempotency, see [Prevent Duplicate iMessages After a Timeout](/blog/prevent-duplicate-imessages).
