Skip to main content

API Basics

Everything you need before making your first call to the Oho REST API: where to send requests, how to authenticate, and the shape of what comes back. These conventions apply to every endpoint, so the Workers & Credentials tutorial and the per-endpoint API Reference assume you've read this page.

Base URLs

Pick the environment you're testing against:

EnvironmentBase URL
Localhttp://localhost:8080/openapi/v1
Staginghttps://api.staging.ohohub.com/openapi/v1
Productionhttps://api.ohohub.com/openapi/v1

The examples throughout these guides use an $OHO_BASE variable so you can switch environments in one place:

export OHO_BASE="http://localhost:8080/openapi/v1"
export OHO_TOKEN="<your-access-token>"

Authentication

Every request carries a bearer token in the Authorization header:

curl -sS "$OHO_BASE/workers" \
-H "Authorization: Bearer $OHO_TOKEN"

Generate a token from Settings → Access Tokens in the Oho app. The token is authorized per entity type — calls to /workers need access to the worker entity, calls to /credentials need access to the credential entity.

Keep tokens secret

Treat your token like a password. Don't commit it to source control or paste it into shared docs — set it as an environment variable as shown above.

For the full picture — token scopes and operations, the 401 vs 403 distinction, safe rotation, and the server-side oauth integration endpoints — see the Authentication & Tokens deep-dive.

Identifiers

Resources are addressed by a synthetic, prefixed ID generated by the server at create time:

EntityID shapeExample
Workerwkr_<id>wkr_V1StGXR8Z5jdHi6B
Credentialcred_<id>cred_8x2Kf9aQ4mN7pLrT
Applicantapp_<id>app_Qz7yT2mB

You never supply these — the server mints them and returns them in the create response and the Location header. Internal URNs are never exposed. To find a worker by your own upstream HRIS identifier instead, use GET /workers?externalId=....

Response envelope

Single-resource reads and writes return a data object with a meta companion:

{
"data": {
"id": "wkr_V1StGXR8Z5jdHi6B",
"type": "worker",
"attributes": { "...": "..." }
},
"meta": { "requestId": "f3c1a0e2-..." }
}

List endpoints return a data array and paging metadata:

{
"data": [{ "id": "wkr_V1StGXR8Z5jdHi6B", "type": "worker", "...": "..." }],
"meta": { "page": 1, "pageSize": 25, "total": 1, "requestId": "..." }
}

pageSize defaults to 25 and is clamped to a maximum of 100.

Soft deletes

DELETE is a soft delete — it sets deleted: true and preserves the record and its history. Soft-deleted resources are excluded from lists unless you pass includeDeleted=true.

Request tracing

Every response carries a server-generated meta.requestId, echoed in the X-Request-Id response header. Quote it in support tickets — it's how Oho finds your call in its logs. If you send your own X-Request-Id (a UUID or 26-character ULID), the server keeps its own id as canonical and echoes yours back in a separate X-Client-Request-Id header so you can line the two systems up.

Errors

All errors carry an error field. Structured failures (conflict, validation, malformed JSON) put a stable category in error and the detail in message; conflicts add a machine-readable code. Simpler failures put the detail straight in error with no message/code. Branch on the HTTP status and code — never on text:

{
"error": "Conflict",
"message": "credential is already linked to applicant app_Qz7yT2mB; use /transfer to replace",
"code": "ALREADY_LINKED"
}
StatusMeaning
200OK
201Created (create endpoints; includes a Location header)
204No Content (successful soft delete)
400Validation error or unparseable filter/path value
401Missing or invalid token
403Authenticated, but not authorized for that entity type
404Resource not found
409Conflict with stored state (code: ALREADY_LINKED, OWNER_MISMATCH, DUPLICATE_ID)
429Rate limited — sets a Retry-After header

For the full picture — conflict recovery, safe retries, idempotency, and matching async webhook deliveries back to a request — see Errors, Retries & Idempotency.

Try it live

Each endpoint in the API Reference has a built-in "Try it" panel, and a live Swagger UI is served at /openapi/swagger-ui/index.html (group openapi-v1).

Ready? Walk through a complete flow in the Workers & Credentials tutorial.