CONNECT AN API
Add your own API¶
Some of the APIs your agent needs are yours alone: an internal service, something behind your firewall, a system only your company runs. You add those to the catalog yourself.
A row you add is private to your organization. Nobody outside it can see it, list it, or read it, until you choose otherwise.
Whose rows are they?¶
Your internal systems are not ours to describe, so the catalog is a registry you can write to.
Names carry their owner¶
The same way a container image does. nginx is the official one; acme/nginx
is Acme's, and both can exist because they were never the same name.
| Name | Whose it is |
|---|---|
slack |
ours, shipped with EKKA, everyone has it |
acme/workday |
Acme's own, private to Acme |
acme/notion |
Acme's own, published so everyone can use it |
Your rows are named <your-org>/<name>, and they keep that name forever,
including after publishing. Anyone using one always knows whose it is.
This is also how you override something. If your Slack sits behind a
corporate proxy, add acme/slack pointing at the proxy. Nothing is shadowed and
nothing has to be renamed, because slack and acme/slack are different names.
Write the file¶
A catalog row is JSON, and the shape below is where you start. Copy it and change the values.
Two commands are worth running first, to see how an API already in the catalog is put together. They show what a row does; the file you write is the shape below:
ekka api describe slack # what it is, and what each operation needs
ekka api spec slack # the plan step for each operation
A minimal one, with a single read:
{
"name": "acme/inventory",
"title": "Acme inventory service",
"base_url": "https://inventory.internal.acme.com",
"auth": { "kind": "bearer" },
"credential_format": "A service token from the inventory team.",
"operations": [
{
"call": "listItems",
"title": "List items",
"verb": "read",
"method": "GET",
"path": "/v1/items",
"inputs": {}
}
]
}
Three things are worth knowing before you write more than that.
A read must be GET. A read-scoped permission can then never produce a
call that changes something. That property is what makes read and write mean
anything, so it is enforced rather than encouraged.
Never put a credential in the file. auth says which kind of credential
the API takes, never the credential itself. That is refused, and it is refused
because a catalog row is readable by everyone who can see it.
The file does not carry a version. EKKA works the number out from what changed between this file and the last version of the same name, and refuses a file that names its own. That is the same rule plans, skills and agents follow.
A row is never edited. Create the next version instead. A plan naming version 1.0.0 keeps running exactly what it ran yesterday, which is the point.
Check it before you add it¶
It names the row it would create, lists the operations in it, and says that nothing was written.
This is not a spell-check. EKKA runs the real insert against the real rules and then throws it away, so the answer is exactly what adding it would say. If something is wrong you get the field:
✗ govern refused this row (invalid_body)
• operations[0].method: a read or list operation must use GET
Create it¶
✓ Added acme/inventory@1.0.0
1 operation, private to this organization.
This version is fixed. An API that changes is the NEXT version, so a plan
naming this one keeps running what it runs today.
No deploy, no upgrade, no waiting. It is in the catalog now:
From here it behaves exactly like any other API. Connect it with
ekka api connect acme/inventory, and the credential goes into your Enclave's
vault on your own machine, as always.
Who picks the version number¶
You do not. Create the file again with your change in it, and EKKA works out the number from what actually changed:
✓ Added acme/inventory@2.0.0
1 operation, private to this organization.
major: input "listItems.region" is now required
The rules are the same ones plans and skills follow, so there is one thing to learn rather than four:
| What you changed | The number moves | Why |
|---|---|---|
Nothing a caller can see: path, method, title, base_url |
patch, 1.0.0 to 1.0.1 |
Where you keep the endpoint is yours. Nobody wrote it down. |
| Added a call, or added an optional input | minor, 1.0.0 to 1.1.0 |
Everything that worked yesterday still works. |
| Made an input required, removed a call, or changed a call's verb | major, 1.0.0 to 2.0.0 |
Something that worked yesterday stops working. |
The number is followed by the reason, in the same words every time, so you can check it against your own diff instead of taking it on trust.
Moving /v1/items to /v2/items is a patch. It changes nothing a plan
wrote down, because a plan names the call, not the URL. Standing between the
two is what the catalog is for.
What EKKA cannot check: the fields that come back¶
Every version after the first prints this:
⚠ EKKA checked the inputs, the calls and the permissions. It cannot see the
RESPONSE FIELDS. If this version returns different fields, that is yours to
keep compatible.
Read it literally. A catalog file says what a call takes and never what it
gives back, so nothing in EKKA can see the difference between a call that
returns {"items": [...]} and the same call returning {"results": [...]}.
Every plan reading items breaks, and the version number says patch.
So when you change what an API returns, that is the one thing the number will not warn anyone about. Treat it the way you would treat any published API of your own: keep the old fields, add new ones beside them, and if you truly must change the shape, make some other part of the call change too so the number moves and people look.
You get the same warning from ekka api catalog validate before anything is
created, which is while the file is still yours to edit.
What if I get a row wrong?¶
A row is never edited, so a wrong base_url or a mistyped path is fixed by
creating the next version. That leaves version 1.0.0 in the menu though, still
offered beside the good one. Archiving is how you take it out.
✓ Archived acme/inventory@1.0.0
It is out of `ekka api list`, and the name on its own no longer resolves to
it. Nothing breaks: a connection pins a version and a plan already holds the
whole call, so anything using it keeps working.
Nothing connected to it breaks. A connection points at a specific version, and a plan already carries the whole request it will send, so neither one looks this row up again. You can still read an archived row by naming its version, which is how you see what an old connection is pinned to:
To undo it:
You can archive rows your own organization added. The ones that ship with EKKA belong to whoever runs your installation.
How do I share it?¶
You may not want to. Most internal APIs should stay private, and that is the default. You never have to do anything to keep a row to yourself.
If a row would be useful to other EKKA customers, offer it:
Nothing changes until we read it and approve. We do that so a row nobody has checked does not reach other customers.
When it is approved it becomes visible to everyone, and it stays acme/notion.
Publishing makes a row visible; it never makes it ours.
How do I tell mine from EKKA's?¶
NAME TITLE WHOSE CREDENTIAL
slack Slack Web API this EKKA bearer
acme/inventory Acme inventory service yours (private) bearer
globex/notion Notion published bearer
| WHOSE | What it means |
|---|---|
this EKKA |
shipped with your installation |
yours |
your organization's row, which you can publish or archive |
published |
another organization's row, offered and approved |
The column answers the question you actually have, which is whether you can change it.
What if I run EKKA myself?¶
On a self-hosted installation your own platform team holds the admin role, so
the rows marked this EKKA are yours to manage too, added with the same
commands. Nothing about this needs us.