{
  "openapi": "3.0.3",
  "info": {
    "title": "Accrue Personal Progress API",
    "version": "1.0.0",
    "description": "Read-only access to the signed-in user's synced Accrue records and evaluator results. Accrue is a record-keeping aid, not a determination of licensure eligibility. Results reflect synced records and may be incomplete until every device has synced."
  },
  "servers": [
    {
      "url": "https://getaccrue.app/api/v1"
    }
  ],
  "tags": [
    {
      "name": "Identity"
    },
    {
      "name": "Progress"
    },
    {
      "name": "Records"
    },
    {
      "name": "Key management"
    },
    {
      "name": "Portal"
    }
  ],
  "paths": {
    "/me": {
      "get": {
        "tags": [
          "Identity"
        ],
        "summary": "Show this API key's account scope",
        "description": "Identity-only exception: this response has no data snapshot, evaluation calendar, or lastSyncedAt metadata, so it returns only data and no meta object.",
        "operationId": "getMe",
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated user ID and key scopes; no email or profile fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/progress": {
      "get": {
        "tags": [
          "Progress"
        ],
        "summary": "Evaluate all ledgers",
        "operationId": "getProgress",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/asOf"
          },
          {
            "$ref": "#/components/parameters/timeZone"
          },
          {
            "$ref": "#/components/parameters/firstWeekday"
          }
        ],
        "responses": {
          "200": {
            "description": "All independent ledger results and sync freshness. Ledger totals must not be added together.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProgressResponse"
                },
                "examples": {
                  "sample": {
                    "summary": "All ledgers with freshness",
                    "value": {
                      "data": {
                        "ledgers": [
                          {
                            "id": "ledger-example",
                            "name": "Board hours",
                            "kind": "board",
                            "authority": "Example Board",
                            "isActive": true,
                            "isPlaceholder": false,
                            "limitations": [],
                            "sources": [
                              "Official board source"
                            ],
                            "headline": {
                              "creditedMinutes": 120,
                              "targetMinutes": 300,
                              "remainingMinutes": 180,
                              "creditedDisplay": "2:00",
                              "targetDisplay": "5:00",
                              "remainingDisplay": "3:00"
                            },
                            "buckets": [],
                            "standing": {
                              "level": "inProgress",
                              "title": "In progress",
                              "detail": "180 minutes remain."
                            },
                            "deadline": null,
                            "deadlineName": "",
                            "pace": {
                              "minutesPerWeek": 60,
                              "completion": "2026-10-23T00:00:00.000Z"
                            },
                            "supervisedWeeks": 0,
                            "requiredSupervisedWeeks": null,
                            "weeksWithIndividualSupervision": 0,
                            "requiredWeeksWithIndividualSupervision": null,
                            "cappedMinutes": 0,
                            "expiredMinutes": 0,
                            "unallocatedMinutes": 0,
                            "warnings": []
                          }
                        ],
                        "freshness": {
                          "lastSyncedAt": "2026-09-25T18:01:00.000Z",
                          "allDevicesSynced": null
                        },
                        "disclaimer": "Accrue is a record-keeping aid, not a determination of licensure eligibility. Synced records may be incomplete until every device has synced."
                      },
                      "meta": {
                        "apiVersion": "1",
                        "asOf": "2026-09-25T18:00:00.000Z",
                        "timeZone": "America/Los_Angeles",
                        "firstWeekday": 1,
                        "lastSyncedAt": "2026-09-25T18:01:00.000Z",
                        "source": "synced_records",
                        "disclaimer": "Accrue is a record-keeping aid, not a determination of licensure eligibility. Synced records may be incomplete until every device has synced."
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/ledgers": {
      "get": {
        "tags": [
          "Progress"
        ],
        "summary": "List evaluated ledgers",
        "operationId": "listLedgers",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/asOf"
          },
          {
            "$ref": "#/components/parameters/timeZone"
          },
          {
            "$ref": "#/components/parameters/firstWeekday"
          },
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "$ref": "#/components/parameters/cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A bounded ledger page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LedgerListResponse"
                },
                "examples": {
                  "sample": {
                    "summary": "A page of ledger summaries",
                    "value": {
                      "data": [
                        {
                          "id": "ledger-example",
                          "name": "Board hours",
                          "kind": "board",
                          "authority": "Example Board",
                          "isActive": true,
                          "isPlaceholder": false,
                          "limitations": [],
                          "sources": [
                            "Official board source"
                          ],
                          "headline": {
                            "creditedMinutes": 120,
                            "targetMinutes": 300,
                            "remainingMinutes": 180,
                            "creditedDisplay": "2:00",
                            "targetDisplay": "5:00",
                            "remainingDisplay": "3:00"
                          },
                          "buckets": [],
                          "standing": {
                            "level": "inProgress",
                            "title": "In progress",
                            "detail": "180 minutes remain."
                          },
                          "deadline": null,
                          "deadlineName": "",
                          "pace": {
                            "minutesPerWeek": 60,
                            "completion": "2026-10-23T00:00:00.000Z"
                          },
                          "supervisedWeeks": 0,
                          "requiredSupervisedWeeks": null,
                          "weeksWithIndividualSupervision": 0,
                          "requiredWeeksWithIndividualSupervision": null,
                          "cappedMinutes": 0,
                          "expiredMinutes": 0,
                          "unallocatedMinutes": 0,
                          "warnings": []
                        }
                      ],
                      "meta": {
                        "apiVersion": "1",
                        "asOf": "2026-09-25T18:00:00.000Z",
                        "timeZone": "America/Los_Angeles",
                        "firstWeekday": 1,
                        "lastSyncedAt": "2026-09-25T18:01:00.000Z",
                        "source": "synced_records",
                        "disclaimer": "Accrue is a record-keeping aid, not a determination of licensure eligibility."
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/ledgers/{id}": {
      "get": {
        "tags": [
          "Progress"
        ],
        "summary": "Get one evaluated ledger",
        "operationId": "getLedger",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/id"
          },
          {
            "$ref": "#/components/parameters/asOf"
          },
          {
            "$ref": "#/components/parameters/timeZone"
          },
          {
            "$ref": "#/components/parameters/firstWeekday"
          }
        ],
        "responses": {
          "200": {
            "description": "A single ledger result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LedgerResponse"
                },
                "examples": {
                  "sample": {
                    "summary": "A single ledger",
                    "value": {
                      "data": {
                        "id": "ledger-example",
                        "name": "Board hours",
                        "kind": "board",
                        "authority": "Example Board",
                        "isActive": true,
                        "isPlaceholder": false,
                        "limitations": [],
                        "sources": [
                          "Official board source"
                        ],
                        "headline": {
                          "creditedMinutes": 120,
                          "targetMinutes": 300,
                          "remainingMinutes": 180,
                          "creditedDisplay": "2:00",
                          "targetDisplay": "5:00",
                          "remainingDisplay": "3:00"
                        },
                        "buckets": [],
                        "standing": {
                          "level": "inProgress",
                          "title": "In progress",
                          "detail": "180 minutes remain."
                        },
                        "deadline": null,
                        "deadlineName": "",
                        "pace": {
                          "minutesPerWeek": 60,
                          "completion": "2026-10-23T00:00:00.000Z"
                        },
                        "supervisedWeeks": 0,
                        "requiredSupervisedWeeks": null,
                        "weeksWithIndividualSupervision": 0,
                        "requiredWeeksWithIndividualSupervision": null,
                        "cappedMinutes": 0,
                        "expiredMinutes": 0,
                        "unallocatedMinutes": 0,
                        "warnings": []
                      },
                      "meta": {
                        "apiVersion": "1",
                        "asOf": "2026-09-25T18:00:00.000Z",
                        "timeZone": "America/Los_Angeles",
                        "firstWeekday": 1,
                        "lastSyncedAt": "2026-09-25T18:01:00.000Z",
                        "source": "synced_records",
                        "disclaimer": "Accrue is a record-keeping aid, not a determination of licensure eligibility."
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/entries": {
      "get": {
        "tags": [
          "Records"
        ],
        "summary": "List this user's records",
        "operationId": "listEntries",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/asOf"
          },
          {
            "$ref": "#/components/parameters/timeZone"
          },
          {
            "$ref": "#/components/parameters/firstWeekday"
          },
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "$ref": "#/components/parameters/cursor"
          },
          {
            "$ref": "#/components/parameters/from"
          },
          {
            "$ref": "#/components/parameters/to"
          }
        ],
        "responses": {
          "200": {
            "description": "A bounded page of records. Entry filters are inclusive civil dates.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Entry"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                },
                "examples": {
                  "sample": {
                    "summary": "Example page",
                    "value": {
                      "data": [
                        {
                          "id": "entry-example",
                          "date": "2026-09-25",
                          "minutes": 60,
                          "duration": "1:00",
                          "activity": "Individual counseling",
                          "activityKind": "direct",
                          "site": null,
                          "supervisor": null,
                          "clientUnit": "unspecified",
                          "clientAge": "unspecified",
                          "modality": "unspecified"
                        }
                      ],
                      "meta": {
                        "apiVersion": "1",
                        "asOf": "2026-09-25T18:00:00.000Z",
                        "timeZone": "America/Los_Angeles",
                        "firstWeekday": 1,
                        "lastSyncedAt": "2026-09-25T18:01:00.000Z",
                        "source": "synced_records",
                        "disclaimer": "Accrue is a record-keeping aid, not a determination of licensure eligibility. Synced records may be incomplete until every device has synced."
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/sites": {
      "get": {
        "tags": [
          "Records"
        ],
        "summary": "List this user's records",
        "operationId": "listSites",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/asOf"
          },
          {
            "$ref": "#/components/parameters/timeZone"
          },
          {
            "$ref": "#/components/parameters/firstWeekday"
          },
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "$ref": "#/components/parameters/cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A bounded page of records. Entry filters are inclusive civil dates.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Site"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                },
                "examples": {
                  "sample": {
                    "summary": "Example page",
                    "value": {
                      "data": [
                        {
                          "id": "site-example",
                          "name": "North Clinic",
                          "kind": "agency",
                          "employment": "employee",
                          "startedOn": null,
                          "endedOn": null
                        }
                      ],
                      "meta": {
                        "apiVersion": "1",
                        "asOf": "2026-09-25T18:00:00.000Z",
                        "timeZone": "America/Los_Angeles",
                        "firstWeekday": 1,
                        "lastSyncedAt": "2026-09-25T18:01:00.000Z",
                        "source": "synced_records",
                        "disclaimer": "Accrue is a record-keeping aid, not a determination of licensure eligibility. Synced records may be incomplete until every device has synced."
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/supervisors": {
      "get": {
        "tags": [
          "Records"
        ],
        "summary": "List this user's records",
        "operationId": "listSupervisors",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/asOf"
          },
          {
            "$ref": "#/components/parameters/timeZone"
          },
          {
            "$ref": "#/components/parameters/firstWeekday"
          },
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "$ref": "#/components/parameters/cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A bounded page of records. Entry filters are inclusive civil dates.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Supervisor"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                },
                "examples": {
                  "sample": {
                    "summary": "Example page",
                    "value": {
                      "data": [
                        {
                          "id": "supervisor-example",
                          "name": "Jordan Lee",
                          "siteNames": [
                            "North Clinic"
                          ],
                          "startedOn": null,
                          "endedOn": null
                        }
                      ],
                      "meta": {
                        "apiVersion": "1",
                        "asOf": "2026-09-25T18:00:00.000Z",
                        "timeZone": "America/Los_Angeles",
                        "firstWeekday": 1,
                        "lastSyncedAt": "2026-09-25T18:01:00.000Z",
                        "source": "synced_records",
                        "disclaimer": "Accrue is a record-keeping aid, not a determination of licensure eligibility. Synced records may be incomplete until every device has synced."
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/tasks": {
      "get": {
        "tags": [
          "Records"
        ],
        "summary": "List this user's records",
        "operationId": "listTasks",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/asOf"
          },
          {
            "$ref": "#/components/parameters/timeZone"
          },
          {
            "$ref": "#/components/parameters/firstWeekday"
          },
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "$ref": "#/components/parameters/cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A bounded page of records. Entry filters are inclusive civil dates.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Task"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                },
                "examples": {
                  "sample": {
                    "summary": "Example page",
                    "value": {
                      "data": [
                        {
                          "id": "task-example",
                          "title": "Confirm placement",
                          "detail": "Confirm the placement approval status.",
                          "source": "placement",
                          "blocksHours": false,
                          "completedOn": null,
                          "dismissedOn": null
                        }
                      ],
                      "meta": {
                        "apiVersion": "1",
                        "asOf": "2026-09-25T18:00:00.000Z",
                        "timeZone": "America/Los_Angeles",
                        "firstWeekday": 1,
                        "lastSyncedAt": "2026-09-25T18:01:00.000Z",
                        "source": "synced_records",
                        "disclaimer": "Accrue is a record-keeping aid, not a determination of licensure eligibility. Synced records may be incomplete until every device has synced."
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/config": {
      "servers": [
        {
          "url": "https://getaccrue.app"
        }
      ],
      "get": {
        "tags": [
          "Portal"
        ],
        "summary": "Get public settings portal configuration",
        "operationId": "getPublicConfig",
        "responses": {
          "200": {
            "description": "Public Firebase web-client configuration only.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "firebase": {
                      "type": "object",
                      "properties": {
                        "apiKey": {
                          "type": "string"
                        },
                        "authDomain": {
                          "type": "string"
                        },
                        "projectId": {
                          "type": "string"
                        },
                        "appId": {
                          "type": "string"
                        }
                      }
                    },
                    "apiBaseUrl": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/account/keys": {
      "servers": [
        {
          "url": "https://getaccrue.app"
        }
      ],
      "get": {
        "tags": [
          "Key management"
        ],
        "summary": "List this account\u2019s API key metadata",
        "operationId": "listApiKeys",
        "security": [
          {
            "firebaseIdToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Metadata only; full key values are not returned after creation.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ApiKeyMetadata"
                      }
                    }
                  }
                },
                "examples": {
                  "sample": {
                    "summary": "No API keys yet",
                    "value": {
                      "data": []
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, expired, revoked, or deleted-account credential.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Key management"
        ],
        "summary": "Create a one-time API key",
        "operationId": "createApiKey",
        "security": [
          {
            "firebaseIdToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 60
                  },
                  "scopes": {
                    "type": "array",
                    "minItems": 1,
                    "uniqueItems": true,
                    "default": [
                      "progress:read"
                    ],
                    "description": "Must include progress:read.",
                    "items": {
                      "type": "string",
                      "enum": [
                        "progress:read",
                        "records:read"
                      ]
                    }
                  },
                  "expiresInDays": {
                    "type": "integer",
                    "enum": [
                      30,
                      90,
                      365
                    ],
                    "default": 90
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Full token value is returned exactly once.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "key",
                    "data"
                  ],
                  "properties": {
                    "key": {
                      "type": "string",
                      "description": "Store securely. Never returned again."
                    },
                    "data": {
                      "$ref": "#/components/schemas/ApiKeyMetadata"
                    }
                  }
                },
                "examples": {
                  "sample": {
                    "summary": "Key returned once at creation",
                    "value": {
                      "key": "accrue_live_REDACTED_ONE_TIME_VALUE",
                      "data": {
                        "id": "AbCdEf0123456789",
                        "name": "Muse connection",
                        "prefix": "accrue_live_AbCdEf0123456789",
                        "scopes": [
                          "progress:read"
                        ],
                        "createdAt": "2026-09-25T18:00:00.000Z",
                        "expiresAt": "2026-12-24T18:00:00.000Z",
                        "lastUsedAt": null,
                        "revokedAt": null
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or unknown query parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, expired, revoked, or deleted-account credential.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Recent sign-in required or request origin rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Five active keys already exist.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Request limit reached.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/account/keys/{id}": {
      "servers": [
        {
          "url": "https://getaccrue.app"
        }
      ],
      "parameters": [
        {
          "$ref": "#/components/parameters/keyId"
        }
      ],
      "delete": {
        "tags": [
          "Key management"
        ],
        "summary": "Revoke an API key",
        "operationId": "revokeApiKey",
        "security": [
          {
            "firebaseIdToken": []
          }
        ],
        "responses": {
          "204": {
            "description": "Revoked, or already absent from this account."
          },
          "401": {
            "description": "Missing, invalid, expired, revoked, or deleted-account credential.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Request origin rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Accrue API key",
        "description": "Use the one-time key returned by the settings portal. Send only in Authorization; never place it in a URL or request body."
      },
      "firebaseIdToken": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Firebase ID token",
        "description": "Firebase Auth ID token from the existing signed-in account. Key creation requires auth_time within 10 minutes."
      }
    },
    "parameters": {
      "asOf": {
        "name": "asOf",
        "in": "query",
        "required": false,
        "description": "Evaluation instant as ISO 8601 UTC. Future instants are rejected. Defaults to the current instant.",
        "schema": {
          "type": "string",
          "format": "date-time"
        },
        "example": "2026-09-26T12:00:00Z"
      },
      "timeZone": {
        "name": "timeZone",
        "in": "query",
        "required": false,
        "description": "IANA time zone used for calendar evaluation. Defaults to UTC; callers should pass the iPhone's time zone.",
        "schema": {
          "type": "string",
          "default": "UTC"
        },
        "example": "America/Los_Angeles"
      },
      "firstWeekday": {
        "name": "firstWeekday",
        "in": "query",
        "required": false,
        "description": "Calendar first weekday, where 1 is Sunday and 7 is Saturday. Defaults to 1.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 7,
          "default": 1
        }
      },
      "limit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "description": "Page size.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 200,
          "default": 100
        }
      },
      "cursor": {
        "name": "cursor",
        "in": "query",
        "required": false,
        "description": "Opaque continuation cursor returned in response metadata. It is scoped to this user, collection and filter.",
        "schema": {
          "type": "string",
          "maxLength": 512
        }
      },
      "id": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "from": {
        "name": "from",
        "in": "query",
        "required": false,
        "description": "Inclusive entry start date as an ISO civil date.",
        "schema": {
          "type": "string",
          "format": "date"
        }
      },
      "to": {
        "name": "to",
        "in": "query",
        "required": false,
        "description": "Inclusive entry end date as an ISO civil date.",
        "schema": {
          "type": "string",
          "format": "date"
        }
      },
      "keyId": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "pattern": "^[A-Za-z0-9_-]{16}$"
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error",
          "requestId"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            }
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          }
        }
      },
      "Meta": {
        "type": "object",
        "required": [
          "apiVersion",
          "asOf",
          "timeZone",
          "firstWeekday",
          "lastSyncedAt",
          "source",
          "disclaimer"
        ],
        "properties": {
          "apiVersion": {
            "type": "string",
            "enum": [
              "1"
            ]
          },
          "asOf": {
            "type": "string",
            "format": "date-time"
          },
          "timeZone": {
            "type": "string"
          },
          "firstWeekday": {
            "type": "integer",
            "minimum": 1,
            "maximum": 7
          },
          "lastSyncedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "source": {
            "type": "string",
            "enum": [
              "synced_records"
            ]
          },
          "disclaimer": {
            "type": "string"
          },
          "nextCursor": {
            "type": "string"
          }
        },
        "example": {
          "apiVersion": "1",
          "asOf": "2026-09-25T18:00:00.000Z",
          "timeZone": "America/Los_Angeles",
          "firstWeekday": 1,
          "lastSyncedAt": "2026-09-25T18:01:00.000Z",
          "source": "synced_records",
          "disclaimer": "Accrue is a record-keeping aid, not a determination of licensure eligibility. Synced records may be incomplete until every device has synced."
        }
      },
      "MeResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "uid": {
                "type": "string"
              },
              "scopes": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "progress:read",
                    "records:read"
                  ]
                }
              }
            }
          }
        }
      },
      "ProgressResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "ledgers": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Ledger"
                }
              },
              "freshness": {
                "type": "object",
                "properties": {
                  "lastSyncedAt": {
                    "type": "string",
                    "format": "date-time",
                    "nullable": true
                  },
                  "allDevicesSynced": {
                    "type": "boolean",
                    "nullable": true
                  }
                }
              },
              "disclaimer": {
                "type": "string"
              }
            }
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "LedgerListResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Ledger"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "LedgerResponse": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Ledger"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "RecordListResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "Ledger": {
        "type": "object",
        "required": [
          "id",
          "name",
          "kind",
          "authority",
          "isActive",
          "isPlaceholder",
          "limitations",
          "sources",
          "headline",
          "buckets",
          "standing",
          "deadline",
          "deadlineName",
          "pace",
          "supervisedWeeks",
          "requiredSupervisedWeeks",
          "weeksWithIndividualSupervision",
          "requiredWeeksWithIndividualSupervision",
          "cappedMinutes",
          "expiredMinutes",
          "unallocatedMinutes",
          "warnings"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "kind": {
            "type": "string"
          },
          "authority": {
            "type": "string"
          },
          "isActive": {
            "type": "boolean"
          },
          "isPlaceholder": {
            "type": "boolean"
          },
          "limitations": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "headline": {
            "$ref": "#/components/schemas/Measure"
          },
          "buckets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LedgerBucket"
            }
          },
          "standing": {
            "$ref": "#/components/schemas/Standing"
          },
          "deadline": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "deadlineName": {
            "type": "string"
          },
          "pace": {
            "type": "object",
            "nullable": true,
            "required": [
              "minutesPerWeek",
              "completion"
            ],
            "properties": {
              "minutesPerWeek": {
                "type": "integer"
              },
              "completion": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "supervisedWeeks": {
            "type": "integer"
          },
          "requiredSupervisedWeeks": {
            "type": "integer",
            "nullable": true
          },
          "weeksWithIndividualSupervision": {
            "type": "integer"
          },
          "requiredWeeksWithIndividualSupervision": {
            "type": "integer",
            "nullable": true
          },
          "cappedMinutes": {
            "type": "integer"
          },
          "expiredMinutes": {
            "type": "integer"
          },
          "unallocatedMinutes": {
            "type": "integer"
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "example": {
          "id": "ledger-example",
          "name": "Board hours",
          "kind": "board",
          "authority": "Example Board",
          "isActive": true,
          "isPlaceholder": false,
          "limitations": [],
          "sources": [
            "Official board source"
          ],
          "headline": {
            "creditedMinutes": 120,
            "targetMinutes": 300,
            "remainingMinutes": 180,
            "creditedDisplay": "2:00",
            "targetDisplay": "5:00",
            "remainingDisplay": "3:00"
          },
          "buckets": [],
          "standing": {
            "level": "inProgress",
            "title": "In progress",
            "detail": "180 minutes remain."
          },
          "deadline": null,
          "deadlineName": "",
          "pace": {
            "minutesPerWeek": 60,
            "completion": "2026-10-23T00:00:00.000Z"
          },
          "supervisedWeeks": 0,
          "requiredSupervisedWeeks": null,
          "weeksWithIndividualSupervision": 0,
          "requiredWeeksWithIndividualSupervision": null,
          "cappedMinutes": 0,
          "expiredMinutes": 0,
          "unallocatedMinutes": 0,
          "warnings": []
        }
      },
      "Measure": {
        "type": "object",
        "required": [
          "creditedMinutes",
          "targetMinutes",
          "remainingMinutes",
          "creditedDisplay",
          "targetDisplay",
          "remainingDisplay"
        ],
        "properties": {
          "creditedMinutes": {
            "type": "integer"
          },
          "targetMinutes": {
            "type": "integer",
            "nullable": true
          },
          "remainingMinutes": {
            "type": "integer",
            "nullable": true
          },
          "creditedDisplay": {
            "type": "string"
          },
          "targetDisplay": {
            "type": "string",
            "nullable": true
          },
          "remainingDisplay": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "ApiKeyMetadata": {
        "type": "object",
        "required": [
          "id",
          "name",
          "prefix",
          "scopes",
          "createdAt",
          "expiresAt",
          "lastUsedAt",
          "revokedAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "prefix": {
            "type": "string",
            "description": "Non-secret key prefix."
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "progress:read",
                "records:read"
              ]
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "lastUsedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "revokedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "LedgerBucket": {
        "type": "object",
        "required": [
          "id",
          "name",
          "unit",
          "creditedMinutes",
          "targetMinutes",
          "remainingMinutes",
          "creditedDisplay",
          "targetDisplay",
          "remainingDisplay"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "unit": {
            "type": "string"
          },
          "creditedMinutes": {
            "type": "integer"
          },
          "targetMinutes": {
            "type": "integer",
            "nullable": true
          },
          "remainingMinutes": {
            "type": "integer",
            "nullable": true
          },
          "creditedDisplay": {
            "type": "string"
          },
          "targetDisplay": {
            "type": "string",
            "nullable": true
          },
          "remainingDisplay": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "Standing": {
        "type": "object",
        "required": [
          "level",
          "title",
          "detail"
        ],
        "properties": {
          "level": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "detail": {
            "type": "string"
          }
        }
      },
      "Pace": {
        "type": "object",
        "required": [
          "minutesPerWeek",
          "completion"
        ],
        "properties": {
          "minutesPerWeek": {
            "type": "integer"
          },
          "completion": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Entry": {
        "type": "object",
        "required": [
          "id",
          "date",
          "minutes",
          "duration",
          "activity",
          "activityKind",
          "site",
          "supervisor",
          "clientUnit",
          "clientAge",
          "modality"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "date": {
            "type": "string",
            "format": "date",
            "description": "Civil date in the requested time zone."
          },
          "minutes": {
            "type": "integer"
          },
          "duration": {
            "type": "string",
            "pattern": "^\\d+:\\d{2}$"
          },
          "activity": {
            "type": "string"
          },
          "activityKind": {
            "type": "string"
          },
          "site": {
            "type": "string",
            "nullable": true
          },
          "supervisor": {
            "type": "string",
            "nullable": true
          },
          "clientUnit": {
            "type": "string"
          },
          "clientAge": {
            "type": "string"
          },
          "modality": {
            "type": "string"
          }
        },
        "example": {
          "id": "entry-example",
          "date": "2026-09-25",
          "minutes": 60,
          "duration": "1:00",
          "activity": "Individual counseling",
          "activityKind": "direct",
          "site": null,
          "supervisor": null,
          "clientUnit": "unspecified",
          "clientAge": "unspecified",
          "modality": "unspecified"
        }
      },
      "Site": {
        "type": "object",
        "required": [
          "id",
          "name",
          "kind",
          "employment",
          "startedOn",
          "endedOn"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "kind": {
            "type": "string"
          },
          "employment": {
            "type": "string"
          },
          "startedOn": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "endedOn": {
            "type": "string",
            "format": "date",
            "nullable": true
          }
        },
        "example": {
          "id": "site-example",
          "name": "North Clinic",
          "kind": "agency",
          "employment": "employee",
          "startedOn": null,
          "endedOn": null
        }
      },
      "Supervisor": {
        "type": "object",
        "required": [
          "id",
          "name",
          "siteNames",
          "startedOn",
          "endedOn"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "siteNames": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "startedOn": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "endedOn": {
            "type": "string",
            "format": "date",
            "nullable": true
          }
        },
        "example": {
          "id": "supervisor-example",
          "name": "Jordan Lee",
          "siteNames": [
            "North Clinic"
          ],
          "startedOn": null,
          "endedOn": null
        }
      },
      "Task": {
        "type": "object",
        "required": [
          "id",
          "title",
          "detail",
          "source",
          "blocksHours",
          "completedOn",
          "dismissedOn"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "detail": {
            "type": "string"
          },
          "source": {
            "type": "string"
          },
          "blocksHours": {
            "type": "boolean"
          },
          "completedOn": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "dismissedOn": {
            "type": "string",
            "format": "date",
            "nullable": true
          }
        },
        "example": {
          "id": "task-example",
          "title": "Confirm placement",
          "detail": "Confirm the placement approval status.",
          "source": "placement",
          "blocksHours": false,
          "completedOn": null,
          "dismissedOn": null
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid or unknown query parameter.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing, invalid, expired, revoked, or deleted-account credential.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Forbidden": {
        "description": "The key lacks the required scope.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "The resource is not visible to this account.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "TooLarge": {
        "description": "The complete dataset exceeds the evaluation limit; no partial data is returned.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unavailable": {
        "description": "Evaluation or synced data is temporarily unavailable; no partial result is returned.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Request limit reached.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  }
}
