Customer tenant API
The endpoints in Partner API reference manage your fleet: provisioning customers, minting leases, vouching workers, setting entitlements. This page covers the other half - driving what is inside a customer organization, so the people using your product never sign in to Yekar.AI.
Everything lives under /api/partner/v1/organizations/{orgId} and mirrors the product surface: agents and flows, connections and credentials, domains and members, triggers and schedules, sessions and runs, approvals, knowledge, apps, webhooks, events, evals, and organization settings.
How a request is authorized
Three things identify every call, and each is checked against the one before it:
POST /api/partner/v1/organizations/{orgId}/automations/{id}/publish
Authorization: Bearer ykp_00000000-0000-4000-8000-000000000001.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
X-Yekar-Subject: your-user-id-42
| Part | What it proves |
|---|---|
Authorization: Bearer ykp_… | Which platform is calling. |
{orgId} in the path | Which customer - it must be an active follower of that platform. |
X-Yekar-Subject | Which provisioned person is acting. |
The credential above is an obviously fake, structurally valid example.
Because the organization is addressed in the path rather than baked into a token, one long-lived key reaches your whole fleet. A nightly sweep across 500 customers is 500 calls on one key, not 500 leases.
Your key is an attestation, not an authority
This is the part worth internalizing, because it decides how you design your integration.
A ykp_ key proves who is asking. It confers no permission of its own. What a call may do is decided entirely by the org and domain roles of the person named in X-Yekar-Subject - evaluated by the same permission system that governs someone clicking in the Yekar.AI UI.
So the model is: when your platform needs to do something that requires a permission, provision a user who holds that permission, and act as them.
You provision that person with POST /organizations/{orgId}/workers:
{
"partnerSubject": "your-user-id-42",
"orgRole": "admin",
"domains": [{ "domainId": "…", "domainRole": "editor" }]
}
domains is declarative when you send it: after the call that person holds exactly the roles listed, and any role you omit is removed. Omit the field entirely and their existing roles are left alone. That is what lets you narrow access as well as widen it.
orgRole is admin or member. Organization administration - settings, AI provider keys and inviting Members - requires admin. Creating domains may also be allowed for Members by organization policy. The organization owner's role cannot be changed by a vouch; that request is refused rather than silently ignored.
Which role for which job
Roles are the same everywhere, so you can reason about them once rather than per customer.
| To do this | The subject needs |
|---|---|
| Read domain agents, flows, ordinary sessions and knowledge | Any role in that domain (viewer or above) |
| Start a published agent/flow or participate in their own session | Any role in that domain |
| Participate in a teammate's domain session; manage triggers and webhooks | operator, editor or owner in that domain |
| Decide a domain-routed approval | The domain's approval policy and any Flow gate role floor; defaults to operator or above |
| Author agents, flows and knowledge; start evaluations or draft tests | editor or owner in that domain |
| Decide OCR spending for scanned documents | Organization admin |
| Manage domain shared connections and credentials | Domain owner |
| Manage domain members and assign any domain role | Domain owner, or organization admin across its domains |
| Organization settings, AI keys, invitations for Members | Organization admin |
| Create domains | Organization admin, or member when organization policy allows it |
An organization Admin cannot read someone else's personal chat or bypass domain permissions. Linked Builder conversations require current edit permission on their subject agent. See Roles and permissions for the complete matrices, ownership rules and approval exceptions.
A subject provisioned in no domain can authenticate and will be refused everything domain-scoped - which is a useful default for a service identity that should only touch one area.
What this is not
Roles bound the blast radius of a call and make the audit trail name a real person. They are not a boundary against you: your platform may vouch anyone into any role in its own followers. What bounds you is the organization check - a key reaches only organizations its own platform provisioned.
Refusals
Every break in the chain answers the same 404: an unknown key, another platform's organization, a missing or unknown X-Yekar-Subject, a revoked mapping, a deactivated membership, a detached follower. They are deliberately indistinguishable, so a key cannot be used to discover which organizations exist or which of another platform's people are active.
Once the chain resolves, refusals are the ordinary product ones - 403 when the acting person lacks the permission, 404 for a record they cannot see.
Starting work
Three endpoints start an execution and accept an end user's own credential for the integrations it runs on:
POST /organizations/{orgId}/sessions- open a conversationPOST /organizations/{orgId}/sessions/{sessionId}/messages- continue onePOST /organizations/{orgId}/automations/{id}/sessions- fire one run
They take callerCredentials exactly as the caller credentials contract describes, and reconcile it against what the target binds at caller identity. A credential for an integration the target does not bind at caller identity is refused by name rather than accepted and ignored.
A credential is scoped to the single execution the request seeds and is never stored as a reusable connection. On POST /sessions, it must accompany a message: a session opened with nothing said has no execution to authorize, and sending one anyway is refused with CALLER_TOKENS_NO_ANCHOR.
POST /automations/{id}/test-runs and POST /automations/{id}/bulk-retry refuse callerCredentials by name. Both run on stored identity by construction, so a supplied token could only ever be silently ignored.
Not available through this API
| Why | What to do instead | |
|---|---|---|
| OAuth connections | Connecting Google, Microsoft, Slack and the rest requires the end user's browser to reach the vendor's consent screen and return to a Yekar.AI URL. No server-to-server call can stand in for a screen a person must see and approve. | Key-based integrations are fully API-driven. For OAuth ones, register your own client under OAuth apps so the consent screen carries your application name, then have the user complete the connect flow. |
Everything else in the product is reachable, including document upload (single and streamed multi-file batches with per-document outcomes), OCR preflight and decisions, web crawl into knowledge, and session file transfer. Uploaded documents follow the same journey as in the product: first successful extraction publishes automatically as the acting subject, and a scanned document waits on an OCR decision - an org-admin subject's call to …/ocr-decision - unless the organization's standing OCR authorization is set.
Worked example: onboarding a customer end to end
1. POST /organizations → customer org
2. POST /organizations/{orgId}/workers → an admin subject
3. POST /organizations/{orgId}/domains → shape the org
4. POST /organizations/{orgId}/users → invite their people
(whitelabel: returns an activation link, sends no Yekar.AI-branded mail)
5. POST /organizations/{orgId}/domains/{id}/connections → their credentials
6. POST /organizations/{orgId}/domains/{id}/automations → author an agent
7. PATCH .../automations/{id}/setup → POST .../setup/publish
8. POST /organizations/{orgId}/automations/{id}/webhooks → completion callbacks
9. POST /organizations/{orgId}/sessions → talk to it
Steps 3–7 need a subject with the roles that step requires. Steps 5 and 6 are the ones people miss: connections need owner on the domain, authoring needs editor.