🔑

pyicloud API Overview and Actions

Dec 7, 2025

Summary

  • PyiCloud is a Python wrapper for iCloud web services using the requests library.
  • Provides programmatic access to authentication, devices, Find My iPhone, calendar, contacts, files (Ubiquity and iCloud Drive), and photo library.
  • Authentication supports username/password, keyring storage, and China mainland accounts.
  • Supports two-step (2SA) and two-factor authentication (2FA) flows with guidance for verification and trusting sessions.
  • File and photo APIs return response objects compatible with requests for streaming and download.

Action Items

  • (now – user) Review authentication options and decide whether to use keyring storage for passwords.
  • (now – developer) Implement handling for china_mainland=True if targeting China Apple IDs.
  • (now – integrator) Add 2FA/2SA handling in any automation that logs into iCloud programmatically.
  • (now – maintainer) Recommend opening file handles in binary mode for uploads/downloads to avoid decoding errors.

Authentication

  • Instantiate: PyiCloudService(username, password) or PyiCloudService(username) if password in keyring.
  • Keyring: command-line tool prompts to save password; remove with --delete-from-keyring.
  • China mainland accounts: pass china_mainland=True when creating PyiCloudService.
  • Sessions expire per Apple interval (currently about two months).

Two-Step / Two-Factor Authentication

  • Detect with api.requires_2fa or api.requires_2sa.
  • 2FA flow:
    • Prompt user for code from approved device.
    • Call api.validate_2fa_code(code).
    • If session not trusted, call api.trust_session().
  • 2SA flow:
    • List api.trusted_devices and prompt selection.
    • Send verification with api.send_verification_code(device).
    • Validate with api.validate_verification_code(device, code).

Devices

  • Access all devices via api.devices (dict of device_id: AppleDevice).
  • Index or ID access: api.devices[0] or api.devices['device_id'].
  • Shorthand for first device: api.iphone (may not be actual iPhone).

Find My iPhone

  • Location: api.iphone.location() returns last known coordinates, timestamp, accuracy.
  • Status: api.iphone.status() returns subset like deviceDisplayName, deviceStatus, batteryLevel.
  • Play Sound: api.iphone.play_sound() triggers ringtone and notification; optional subject message.
  • Lost Mode: api.iphone.lost_device(phone_number, message) shows message and allows a call without passcode.

Calendar

  • Fetch events for current month: api.calendar.events()
  • Fetch between dates: api.calendar.events(from_dt, to_dt)
  • Fetch single event details: api.calendar.get_event_detail('CALENDAR', 'EVENT_ID')
  • Calendar webservice only supports fetching events.

Contacts

  • Access via api.contacts.all() to iterate contacts.
  • Contact example fields: firstName, phones (list of {field, label}).
  • Note: excludes federated contacts (e.g., from Facebook).

File Storage (Ubiquity)

  • Rooted at api.files; list top-level entries with api.files.dir().
  • Navigate using filename keys like api.files['comappleNotes']['Documents']['Some Document'].
  • File properties: .name, .modified (datetime), .size, .type.
  • Download: .open() returns a requests response; read .content or use stream=True and response.raw.
  • .open().json() works for JSON files.
  • For large files, use stream=True and read response.raw.

File Storage (iCloud Drive)

  • Rooted at api.drive; API mirrors Ubiquity interface.
  • List and navigate directories with .dir() and indexing.
  • File properties: name, date_modified (UTC), size, type.
  • Download with drive_file.open(stream=True) and copy raw stream to local file.
  • File operations: mkdir, rename, delete on folders/files.
  • Upload: api.drive['Folder'].upload(file_like_object) — open file handles in binary mode.

Photo Library

  • Access via api.photos; main collections: api.photos.all and api.photos.albums.
  • Iterate album to get PhotoAsset objects with id and filename.
  • Download: photo.download() returns response with stream enabled; write response.raw to file.
  • Photo versions available via photo.versions.keys() (e.g., medium, original, thumb).
  • Download specific version: photo.download('thumb') and use photo.versions['thumb']['filename'] for naming.
  • Recommend buffered copy (shutil.copyfileobj) to avoid loading entire file into memory.

Code Samples

  • Additional usage examples available in the repository's CODE_SAMPLES.md file.

Decisions

  • Use keyring storage for convenience when interacting via CLI.
  • Default to streaming downloads for large files/photos to conserve memory.
  • Treat api.drive and api.files APIs as interchangeable patterns for navigation and I/O.

Open Questions

  • Are write operations (creating/updating calendar events or contacts) supported beyond listed fetch capabilities?
  • Any rate limits or API throttling behavior documented for heavy usage?
  • How are errors and exceptions beyond failed login (e.g., network errors, permission errors) surfaced by API?