workinOn Board API

Let any app on the device post to your personal status board.

Build 44 · iOS 26+

Contents

  1. Overview
  2. URL Scheme Commands
  3. Swift Helper — WorkinOnPoster
  4. Notifications → List Entries
  5. Swift Helper — WorkinOnNotificationHelper
  6. Remote Push (APNs)
  7. Shortcuts & Automation
  8. Common Patterns

1. Overview

workinOn maintains a short, ordered list of things you're working on — always visible on your home screen via the Large widget. Beyond personal use, it acts as a personal status board: any iOS app on the same device can post a named status slot, update it, and remove it.

There are three integration paths, each suited to different callers:

Path Best for Delivers when
URL scheme iOS apps, Shortcuts App is foregrounded to handle the URL
Local notification iOS apps, time-based triggers Notification fires (silent) or user taps it
Remote push (APNs) Servers, background delivery Silently, in the background, any time
Requirement workinOn must be installed on the device. The app handles all three paths — no backend required.

2. URL Scheme Commands

All commands use the workinon:// scheme. All text values must be URL-encoded.

CommandURLEffect
Open workinon://open Bring workinOn to the foreground
Add item workinon://add?text=Buy%20milk Append a manual list item
Post status workinon://post?key=myapp&text=Running Upsert a keyed status item (creates or replaces)
Post with photo workinon://post?key=myapp&text=Done&photoID=<id> Upsert with a photo from the library
Remove status workinon://remove?key=myapp Remove a keyed status item
Clear all workinon://clear Remove all items (use carefully)

Key semantics

A key identifies your app's slot on the board. Use your app name or bundle ID (e.g. nagz, com.myapp.status). Keys are case-sensitive. Posting to an existing key replaces the item in place — no duplicates. Status items appear pinned at the top of the list.

Opening from Swift

let url = URL(string: "workinon://post?key=myapp&text=Server%20running")!
UIApplication.shared.open(url)

3. Swift Helper — WorkinOnPoster

Copy Shared/WorkinOnPoster.swift into your iOS app. No dependencies, no configuration. Suitable for: nagz-ios, qross, famster, obo-ios, alities-mobile, pickledballs, workinOn itself.

iOS apps only WorkinOnPoster uses UIApplication.shared.open(). It cannot be used in servers or background extensions that lack a UIApplication. Servers should use the Remote Push path instead.
// Post a text status
WorkinOnPoster.post(key: "nagz", text: "✓ API up · port 9800")

// Post with a photo from the library
WorkinOnPoster.post(key: "nagz", text: "Dashboard", photoID: asset.localIdentifier)

// Remove your slot
WorkinOnPoster.remove(key: "nagz")

// Add a plain manual item (no key)
WorkinOnPoster.add(text: "Fix the auth bug")

Posting images

workinOn stores photos by PHAsset.localIdentifier — it reads from the photo library, no file copying needed. To post an image your app generated:

PHPhotoLibrary.shared().performChanges {
    let req = PHAssetChangeRequest.creationRequestForAsset(from: myUIImage)
    let id = req.placeholderForCreatedAsset?.localIdentifier
    DispatchQueue.main.async {
        WorkinOnPoster.post(key: "myapp", text: "Chart updated", photoID: id)
    }
}

4. Notifications → List Entries

Any local or remote notification can carry a workinon_url key in its userInfo payload. workinOn processes this URL when the notification is delivered (silent) or when the user taps it (alert).

Payload format

{
  "aps": {
    "alert": { "title": "workinOn", "body": "Tap to add to your list" },
    "sound": "default"
  },
  "workinon_url": "workinon://add?text=Standup%20notes"
}

The workinon_url value is any valid workinon:// URL from the table above. All commands work: add, post, remove, clear.

Behavior by delivery context

ContextAlert shown?Command runs
App in foreground, workinon_url present No — silently executed Immediately on delivery
App in background, alert notification Yes When user taps notification
Silent push (content-available: 1) No Immediately in background
App not running, alert notification Yes When user taps notification, launches app

5. Swift Helper — WorkinOnNotificationHelper

Copy Shared/WorkinOnNotificationHelper.swift into your iOS app. Requires UNUserNotificationCenter permission to be granted.

// Add an item when the user taps a notification (5 minutes from now)
WorkinOnNotificationHelper.scheduleAdd(
    text: "Standup notes",
    title: "workinOn",
    body: "Tap to add standup to your list",
    at: Date().addingTimeInterval(300)
)

// Post a silent heartbeat every 5 minutes
WorkinOnNotificationHelper.schedulePost(
    key: "myserver",
    text: "myServer: running",
    silent: true,
    repeating: .everyFiveMinutes
)

// Post daily status at 9am
WorkinOnNotificationHelper.schedulePost(
    key: "myapp.daily",
    text: "Daily check-in",
    at: Calendar.current.date(bySettingHour: 9, minute: 0, second: 0, of: Date())!,
    repeating: .daily
)

// Remove status silently at 6pm
WorkinOnNotificationHelper.scheduleRemove(
    key: "myapp.office",
    silent: true,
    at: Calendar.current.date(bySettingHour: 18, minute: 0, second: 0, of: Date())!
)

// Cancel a scheduled notification
WorkinOnNotificationHelper.cancel(identifier: "my-notification-id")

6. Remote Push (APNs)

Servers can deliver workinOn commands silently via APNs. workinOn processes the workinon_url key from the push payload immediately in the background — no user interaction required.

Best path for servers This is the recommended path for nagzerver, cardzerver, and any other backend that needs to update the board without user interaction.

APNs payload

{
  "aps": {
    "content-available": 1
  },
  "workinon_url": "workinon://post?key=nagzerver&text=%E2%9C%93%20API%20up%20%C2%B7%209800"
}

Python example (nagzerver)

import urllib.parse

def post_workinon_status(key: str, text: str) -> dict:
    """Build APNs payload to post a workinOn status item."""
    encoded_text = urllib.parse.quote(text)
    url = f"workinon://post?key={key}&text={encoded_text}"
    return {
        "aps": {"content-available": 1},
        "workinon_url": url
    }

# Usage:
payload = post_workinon_status("nagzerver", "✓ API up · port 9800")
await send_apns_push(device_token, payload, bundle_id="com.workinon.app")

APNs push headers

HeaderValue
apns-push-typebackground
apns-topiccom.workinon.app
apns-priority5 (low priority for silent)

7. Shortcuts & Automation

workinOn's URL scheme works natively in the Shortcuts app — no configuration required. Use the Open URL action.

Example: "Add to workinOn"

1
Add action: Ask for Input → prompt "What are you working on?" → store in Input
2
Add action: URL Encode → input: Input → store in Encoded
3
Add action: Open URLworkinon://add?text=[Encoded]

Add this shortcut to Siri: "Hey Siri, add to workinOn"

Example: "Post my status"

1
Add action: Open URLworkinon://post?key=mystatus&text=In%20a%20meeting

Personal Automations

In the Shortcuts app, go to Automation → New Automation:

TriggerAction URLEffect
Time of day · 9am · Daily workinon://post?key=morning&text=Morning%20check-in Post daily reminder to board
App opened · Xcode workinon://post?key=coding&text=In%20Xcode Post when you start coding
App closed · Xcode workinon://remove?key=coding Remove when you stop coding
Arrive at location workinon://post?key=location&text=At%20the%20office Post your location status
Leave location workinon://remove?key=location Clear when you leave

8. Common Patterns

Server heartbeat (via APNs)

# Send from nagzerver every 5 minutes via cron or APScheduler
payload = post_workinon_status("nagzerver", "✓ up · " + current_time())
# If the item disappears from the board, the server stopped sending

Build status (iOS app)

// At build start
WorkinOnPoster.post(key: "build", text: "⏳ Build 44 in progress")

// On success
WorkinOnPoster.post(key: "build", text: "✓ Build 44 on TestFlight")

// On failure
WorkinOnPoster.post(key: "build", text: "✗ Build 44 failed")

Time-boxed focus (Notification + remove)

// Post now
WorkinOnPoster.post(key: "focus", text: "Deep work — no interruptions")

// Auto-remove in 90 minutes via silent notification
WorkinOnNotificationHelper.scheduleRemove(
    key: "focus",
    silent: true,
    at: Date().addingTimeInterval(90 * 60)
)

Office hours (Shortcuts automation)

Create two automations: one at 9am posts workinon://post?key=office&text=Available, one at 5pm fires workinon://remove?key=office. The widget always reflects your current availability.

Files to copy into your app Both files are self-contained, zero-dependency Swift. Just copy and use.