# Owedly developer APIs

**Hosts:** https://owedly.ai · https://owedly.net · https://owedly.io
**Project:** owedly-buyer
**Quickstart:** https://owedly.ai/#agent-quickstart · https://owedly.ai/agents

Brand: **Owedly** only.

## Scoped agent connectors (recommended)

Desk: `https://owedly.ai/mcp/desk`. Resolve: `https://owedly.ai/mcp/resolve`.
Use OAuth authorization code with PKCE S256 and the exact workspace URL as the resource. Each workspace has independent read and draft scopes. These tokens do not authorize `/api/v1`.

- [Muse setup](https://owedly.ai/agents/muse.md)
- [Consumer OpenAPI](https://owedly.ai/agents/resolve/openapi.json)
- [Business OpenAPI](https://owedly.ai/agents/desk/openapi.json)
- [Setup](https://owedly.ai/agents)
- [Developer guide](https://owedly.ai/agents/developers)
- [OpenAPI 3.1](https://owedly.ai/agents/openapi.json)
- [Privacy and revocation](https://owedly.ai/agents/privacy)

REST equivalents live under `/api/connectors/v1/{workspace}/tools/{tool}`. They share the MCP validation, scope checks and handlers. Only saved drafts require write scopes; no messaging, settlement acceptance, or money movement is exposed. On Resolve, `POST /api/connectors/v1/resolve/tools/relay_approved_offer` with `resolve:read` returns offers the creditor or agency already approved. relay_approved_offer returns offers the creditor or agency already set and approved for that account, verbatim, with the offer ID and expiry. It never proposes, counters, calculates, negotiates, or changes amounts or terms. Acceptance and payment are not available. Nothing is accepted or paid without the consumer's explicit action.

## Legacy `/api/v1` authentication

- Browser: Supabase session
- Agents: desk-scoped key `owedly_live_…` from signed-in `/app/place` Agent door
  Header: `Authorization: Bearer <key>`
- Resolve (consumer) agents use web doors (`/resolve`). They do not mint desk keys.

## Core

| Method | Path | Purpose |
|--------|------|---------|
| GET | `/api/v1` | Discover |
| GET | `/api/v1/me` | Desk / key identity |
| POST | `/api/v1/agency/invites` | Agency desk: mint `https://owedly.ai/invite/<token>` (`APP_URL`) |
| GET | `/api/v1/agency/invites` | Agency desk: list invite links |
| GET | `/api/v1/agency/invites/peek` | Public peek (`?token=`). Fail-closed on expired/revoked/unknown |
| POST | `/api/v1/agency/invites/redeem` | Attach the signed-in desk as a client of that agency (many-to-many) |
| GET | `/api/v1/agency/clients` | Agency desk: list clients |
| GET | `/api/v1/agency/memberships` | Agencies this buyer/creditor desk has joined |
| POST | `/api/v1/placements` | Place accounts (JSON or CSV; `agency_desk_id`; `?dryRun=1`). `amount` may be omitted, null, or blank (parsed as null, not 0). A real 0 stays 0. A leading `$` and thousands commas are accepted. Non-numeric amount is `invalid_amount`. Saved places auto-start Account Workflow. |
| GET | `/api/v1/placements` | List placements / skip. Each account `amount` is a number or null. `null` means the balance was not provided. |
| POST | `/api/v1/phones/import` | B2B phones; `source` required; `dryRun` preview |
| GET | `/api/v1/inventory/skip` | Honest not-skipped count or unknown |
| POST | `/api/v1/escalations` | Escalate to Joey |
| POST | `/api/agents/route` | First-party TypeSafe door (Jev). `{ text }` → desk / resolve / collect / chargebacks (+ resolve call-vs-letter) |
| GET | `/api/agents/route` | `{ hosted: true\|false, ready.llm, ready.typesafe }` — never the key |
| POST | `/api/reception` | Homepage Ask. Jev-first door routing; LLM only when prose is needed |
| GET | `/api/reception` | `{ ready.llm, ready.typesafe.hosted }` — never the key |

| GET | `/api/v1/workflows/runs` | Action dashboard runs (`?status=`) |
| GET | `/api/v1/workflows/events` | Append-only automation feed |
| POST | `/api/v1/workflows/start` | Start Account Workflow for saved accounts |

Also used by humans: `POST /api/reception`, desk chat routes, identity verify. Place → Action (`/app/action`), not a manual start button.

## Bootstrap files

- `/agents/skill.md`
- `/agents/prompt-resolve.md`
- `/agents/prompt-desk.md`
- `/agents/api.md`

## TypeSafe (Jev)

Jev for structured routing; LLM for long-form chat.

Owedly hosts `TYPESAFE_API_KEY` on Vercel (production, preview, development). First-party routes read `process.env.TYPESAFE_API_KEY` for homepage reception door routing, Ask Owedly intent routing, and `/api/agents/route`. The key is never `NEXT_PUBLIC_*` and never sent to the browser.

Desks can optionally call [TypeSafe System One](https://docs.typesafe.ai/) themselves with **their own** key:

```http
POST https://api.typesafe.ai/v1/systemone
Authorization: Bearer <your_TYPESAFE_API_KEY>
```

Prefer one small Jev Choice (or Noul) per decision. Fail closed if the key is missing — do not invent a route, count, or legal conclusion.

## Web doors

Prefer documented web routes when an API is missing. Fail closed on 404/5xx and missing vendor keys.
