Skip to content

Mobile Sync (iOS Shortcuts & Android Tasker)

Picora does not ship a native mobile app yet. Instead, v0.37.0 introduces a zero-app mobile sync path using the system automation tools already on your phone: iOS Shortcuts on iPhone/iPad, and HTTP Shortcuts or Tasker on Android. All three call the existing POST /v1/images API with your API key.

What you get

  • Manual upload from the Share Sheet (iOS) or a launcher shortcut (Android)
  • Automatic upload when a new photo is taken (iOS Personal Automation / Android Tasker)
  • Public CDN URL copied to clipboard the moment upload completes
  • Bandwidth-aware — videos > 50 MB are not recommended on cellular; the templates respect Wi-Fi-only by default

What you don’t get (limitations)

  • iOS Personal Automation may require a manual tap on iOS 16 and below; iOS 17+ supports fully silent triggering.
  • Bulk historical backfill (> 10,000 photos) is constrained by iOS Shortcut’s ~3-5 minute background time budget (~500 photos per batch). For full library import, use @picora/photo-importer CLI (v0.56.0) instead.

Prerequisites

  • A Picora account (sign up)
  • An API Key with image:write scope (generate one)
  • iOS 16+ for iPhone/iPad, Android 8+ for Android phones

iOS Shortcuts setup

Step 1 — Create the API Key

In Picora’s API Keys page, create a new key with the image:write scope only (least-privilege). Copy the sk_live_... value — you’ll see it only once.

Step 2 — Build the Shortcut

Open the Shortcuts app on iOS, tap + to create a new shortcut, then add these actions in order:

  1. Get Images from Input — receives the photo from the Share Sheet
  2. Get Contents of URL
    • URL: https://api.picora.me/v1/images
    • Method: POST
    • Headers:
      • Authorization: Bearer sk_live_YOUR_KEY
      • X-Picora-Client: shortcut-ios
      • Accept-Language: Device Language (variable)
    • Request Body: Form
      • file: the Image from step 1
      • isPublic: true
  3. Get Dictionary Value — key data.url from the JSON response
  4. Copy to Clipboard — the URL
  5. Show Notification — “Uploaded to Picora: <URL>

In the shortcut’s settings, enable Show in Share Sheet and limit accepted input to Images.

Step 3 — Test it

In Photos, pick any image → tap the share icon → scroll down → tap your Picora Upload shortcut. Within seconds, you’ll see a notification and the URL is on your clipboard. Paste anywhere to verify.

Step 4 (optional) — Automate on photo capture

Open Shortcuts → Automation → +, choose Photo Taken, select Run Immediately (iOS 17+) or leave Ask Before Running on iOS 16. Pick your Picora Upload shortcut. New photos now sync automatically.

Step 5 (v0.55.1) — Upload videos (fire-and-forget)

POST /v1/videos returns 202 Accepted immediately with a videoId. Bunny.net transcodes asynchronously in the cloud — Shortcut does not need to poll. Create a separate “Picora Video Upload” shortcut:

  1. Get Media from Input — Type: Videos
  2. Get Contents of URL
    • URL: https://api.picora.me/v1/videos
    • Method: POST
    • Headers:
      • Authorization: Bearer sk_live_xxx (must include video:write scope)
      • X-Picora-Client: shortcut-ios-video
    • Body: Form, file=step 1 video, isPublic=true
  3. Get Dictionary Value — path data.id
  4. Show Notification — “Picora video submitted for transcoding / ID: <videoId>
  5. (Optional) Copy to Clipboardhttps://center.picora.me/videos/{videoId}

In the Shortcut’s Share Sheet settings, set input type to Videos (or combine with images in one Shortcut using an If branch on media type).

Step 6 (v0.55.1) — Historical photo backfill

iOS Shortcut’s built-in “Find Photos” action combined with server-side sha256 dedup lets you backfill old photos in batches. Re-running the same date window 100% hits dedup, so it never double-charges quota.

Create a new shortcut “Picora Historical Backfill”:

  1. Ask for Input — Type: Date, prompt “Backfill start date?”
  2. Ask for Input — Type: Date, prompt “Backfill end date?”
  3. Find Photos
    • Filter: Date Created is between step 1 and step 2
    • Media: Photos
    • Limit: 500
  4. Repeat with Each (over step 3 results):
    • 4a. Get Contents of URL (same as live upload, with header X-Picora-Client: shortcut-ios-backfill)
    • 4b. Wait 0.5 seconds (avoid hitting the rate limit)
  5. Show Notification — “Processed <step 3 count> photos”

Usage tips:

  • Pick a year-long window per batch, up to 500 photos
  • Mid-batch timeout is harmless — re-run the same window, 100% hits dedup
  • Full library (> 10,000 photos)? Use @picora/photo-importer macOS CLI (v0.56.0) which has no background time budget

Android setup — HTTP Shortcuts (simpler)

HTTP Shortcuts is a free, open-source Android app. No root needed.

  1. Install HTTP Shortcuts from Play Store or F-Droid
  2. Create a new shortcut:
    • Method: POST
    • URL: https://api.picora.me/v1/images
    • Headers: add Authorization: Bearer sk_live_YOUR_KEY and X-Picora-Client: shortcut-android
    • Body type: Form data
    • Form fields:
      • file (type: File) — select Pick file at execution
      • isPublic (type: Text) — value true
  3. Under Scripting → On Success, paste:
    const url = JSON.parse(response.body).data.url;
    copyToClipboard(url);
    showToast("Picora: " + url);
  4. Tap the shortcut from your launcher or add it to the Share Sheet via app settings.

Android setup — Tasker (auto-sync on photo)

Tasker is a paid app (~$3.49) but supports true background automation via the MediaStore content observer.

  1. Install Tasker + AutoTools (optional, for nicer notifications)
  2. Create a Profile:
    • Event → File → File Modified
    • Path: Pictures/
    • Set: include subdirectories
  3. Create a Task:
    • HTTP Request action
      • Method: POST
      • URL: https://api.picora.me/v1/images
      • Headers: Authorization: Bearer sk_live_YOUR_KEY and X-Picora-Client: tasker
      • File parameter: file%evtprm2 (path of new file)
      • Form: isPublic=true
    • Variable Set%url to %http_data.data.url (use the JSON Read action)
    • Notify — “Picora synced: %url”
    • Set Clipboard%url
  4. Under Profile settings, add State → Net → Wifi Connected if you want Wi-Fi-only.

Response headers worth knowing

HeaderMeaning
X-Picora-Duplicate: trueThe same photo (by sha256) is already in your library — Picora returned the existing record without re-uploading. Doesn’t count toward your quota.
X-Picora-Idempotency-Replay: trueYour client sent Idempotency-Key and this is a cached response from a previous identical request.

When testing automation, retrying with the same photo should produce X-Picora-Duplicate: true and the same URL.

Optional — batch hash precheck before bulk sync

If you’re writing a heavier automation that walks the entire camera roll (Shortcuts/Tasker won’t usually do this, but a power user might), call POST /v1/images/exists first with up to 200 SHA-256 hashes. The server returns which hashes are already in your library — skip those, upload the rest.

Terminal window
curl -X POST https://api.picora.me/v1/images/exists \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"hashes": ["aaaa...", "bbbb..."]}'

Response:

{
"success": true,
"data": {
"existing": { "aaaa...": { "id": "abc123", "url": "https://media.picora.me/abc123.jpg" } },
"missing": ["bbbb..."]
}
}

Troubleshooting

401 Unauthorized — API key is missing, malformed, or revoked. Regenerate at center.picora.me/api-keys.

403 Forbidden, code QUOTA_EXCEEDED — your storage or bandwidth quota is full. Check usage in Quota & Usage.

422 Validation error — usually wrong Content-Type or missing file field. Ensure the shortcut uses multipart/form-data (Form body), not raw JSON.

413 Payload Too Large — file > 10 MB on the free plan. Resize before uploading or upgrade your plan.

Shortcut runs but no URL appears — the response path is data.url, not just url. Double-check the JSON-parsing step.

What’s coming next

  • Native iOS / Android apps (v0.38+, technology stack still under evaluation)
  • TUS resumable upload for large videos (v0.37.0 backend already ships the API)
  • Incremental sync via GET /v1/sync/state cursor (v0.37.0 backend ready) — clients can pull deltas instead of full re-syncs

See Iteration v0.37.0 for the full backend changelog.