Choose the API origin
Production:https://app.ohmyho.st. Use https://dev.app.ohmyho.st only when you deliberately selected the development platform. Paths below already include /v1.
Create your user token from Profile → API Tokens or the CLI, then load it through your shell or automation platform’s secret storage.
Read the current account
GET /v1/me returns actor_id, the current user’s or user API-token owner’s email, organization_ids and organizations containing each scoped workspace’s id and current name. Machine-to-machine credentials return a null email. The two organization lists have the same scope and order. Use the IDs in requests and the names and email to check the intended account.
Requests that change state
Use the exact method, schema and permissions in the endpoint reference. SupplyIdempotency-Key where required and retain it with the original request. After an uncertain response, replay the same key and payload; a new key can create new work.
Accepted asynchronous mutations return an operation ID. Read GET /v1/operations/{operation_id} and follow its polling guidance. Operation success still requires checking the expected application outcome.
Errors and pagination
An error usesapplication/problem+json with a stable code, retryable, suggested_action and request_id; type links the page for that code. Decide by code, not HTTP status alone. 402 means credits, Paid access or a Stop budget block the request. 409 means a prerequisite must change, for example github_connection_required, mail_domain_required, deployment_plan_expired or etag_mismatch. Repeat an unchanged request only when retryable is true; for 429, wait for Retry-After. An uncertain mutation keeps its original request and key; never retry every error as new work.
List endpoints return their documented cursor. Send that cursor on the next request and stop when it is absent. Errors, limits and polling.
Source bindings and managed versions
ReadGET /v1/projects/{project_id}/source before choosing how to save files. Its default GitHub response keeps the released status fields. Request ?include_binding=true before using source-connection or generation guards; managed source returns its full binding in either view. Preserve the selected project and its existing source. Sources and versions explains the local and connected-chat workflows.
The API contract names the operations below. Use the endpoint’s exact request schema and keep its Idempotency-Key with the original request.
REST edit bodies use
content_base64; null deletes a path. MCP can accept content_text and returns UTF-8 text when available. Do not mix those transport shapes. Every changed file retains its executable flag. Read the current generation and reconcile changes before supplying expected_commit_sha; a fresh remote head does not make stale local files current.
Complete snapshots
A complete tree uses one prepared upload, exact per-file receipts and a final manifest. Native MCP clients follow the complete-tree flow; the local source publisher performs staging and saves the checkout’s confirmed base.
For initialize, the project must be genuinely unbound with no pending initialization: use generation
0, null source connection and null parent commit. For commit, use the actual managed connection/generation and the reconciled parent SHA. For switch, retain the original GitHub connection/generation and use a null parent commit. A switch requires the customer’s explicit source choice; it does not create another project or import GitHub history.
REST blob bodies contain the actual base64 file contents, their canonical SHA-256 and executable flag. Remote source_blob_put accepts exactly one content_text or content_base64, computes the hash and byte length from the real bytes, and returns a validated receipt. Retain each returned {path, sha256, byte_length, executable} exactly. Do not invent hashes or use a receipt from another upload.
Stage every file that should remain, including unchanged retained files. Build the complete final files array from receipts of this upload; every staged path must occur exactly. An incomplete or altered manifest is rejected. Omit a previously committed file without staging it to delete it from the next tree. Normal finalize includes the original expected_source_generation; switch also supplies the upload ID and original connection ID.
Keep the same operation, manifest and step keys after uncertainty. Observe the receipt before replaying; sealed or committed uploads must not be restaged. sealed can identify an unpushed candidate; only a succeeded operation and committed receipt confirm the version. getManagedSourceUpload returns state and commit, not a file inventory. Recover a lost blob receipt by replaying its identical request/key. A committed receipt’s commit_sha is that upload’s exact version even if the current source head later advances. Initialize/switch change source generation; normal commits use parent-SHA concurrency checks. None of these source operations deploys, changes project addresses or reverts database data.
The current bounds are 2,000 files, 2 MiB decoded per file/change batch and 8 MiB for the tree. Path and secret restrictions apply to every entry. For local snapshots, the CLI source publisher already implements this staged flow and completes the checkout’s own cached base.