Getting Started with the CERTEN Gateway API
This guide walks through the core workflows of the CERTEN Gateway API using curl examples.
Base URL
https://gateway.kompendium.co
Confirm it before anything else — one request, no key needed:
curl https://gateway.kompendium.co/v1/health # {"status":"healthy"}
The live OpenAPI spec is public at /docs (JSON at
/docs/json). It is generated from the running server, so it is
authoritative for request and response shapes — including every endpoint this guide does not cover. When
this page and the spec disagree, the spec is right.
The SDK and CLI default to the same host and both honor a CERTEN_API_URL override, so a staging or
self-hosted gateway needs no code change:
export CERTEN_API_URL="https://gateway.staging.internal"
1. Get an API Key
Sign in at https://gateway.kompendium.co/portal and mint one. It is self-service — Google or email sign-in, no ticket, no waiting on anyone. The portal is also where you rotate keys, revoke them, and invite teammates.
The key is shown once, in the format ck_live_.... It cannot be retrieved again; mint a new one
if you lose it.
export API_KEY="ck_live_your_key_here"
Prefer the CLI? It stores the key in your OS keyring rather than a shell history file:
npm install -g @certen.io/cli
certen auth login --api-key "$API_KEY"
New organizations start with sandbox limits (a capped credit grant and a small number of identities), which is enough to run everything in this guide. Ask an operator to approve the org when you need more.
2. Generate a signing key
An identity is controlled by an Ed25519 key that you hold. CERTEN never has it, which is why nobody here can move your assets — and also why you have to make one before there is anything to create.
certen keys generate --name dev
That prints a public_key and a public_key_hash, encrypts the private key with your passphrase,
and writes it to ~/.certen/keys/dev.json (mode 0600).
If you are producing the key yourself rather than with the CLI: public_key_hash is
sha256(raw 32-byte Ed25519 public key) — the hash of the key BYTES, not of its hex spelling and
not of the SPKI DER. Getting this wrong creates an identity bound to a key you do not have, and the
failure does not surface until the first signature is rejected.
# The equivalent in Node, if you are not using the CLI
node -e "const c=require('crypto');const{publicKey}=c.generateKeyPairSync('ed25519');
const spki=publicKey.export({format:'der',type:'spki'});const raw=spki.subarray(spki.length-32);
console.log('public_key ',raw.toString('hex'));
console.log('public_key_hash',c.createHash('sha256').update(raw).digest('hex'));"
3. Create an Identity
An identity is an Accumulate ADI with associated key book, key page, and optional chain accounts.
certen identity create --name my-company --sign-with dev \
--chains ethereum-sepolia,polygon-amoy
Or over HTTP, supplying the key material from the previous step:
curl -X POST https://gateway.kompendium.co/v1/identity \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"name": "my-company",
"public_key_hash": "c2446def78b3ec4de53ee1939cf1b5e2bfaf8bd8c80a2821b4b05bea1ad44b83",
"public_key": "e6f9930f50298ba7d1cad45e902cb8eaa5ba6b3752a6666a1ca0c128721d6a0b",
"chains": ["ethereum-sepolia", "polygon-amoy"],
"credits": 50000
}'
Send an Idempotency-Key on every POST. A network error is otherwise indistinguishable from
success, and a blind retry can create a second identity against your quota.
Response — 202 Accepted, not 200. Provisioning writes an ADI, key book, and key page to
Accumulate, which takes tens of seconds, so the status is creating and chain_accounts is still
empty:
{
"identity": {
"id": "0fbdbe8c-4895-4a9e-88e4-ae8f852c67a9",
"adi_url": "acc://my-company.acme",
"book_url": "acc://my-company.acme/book",
"key_page_url": "acc://my-company.acme/book/1",
"status": "creating",
"chain_accounts": [],
"credit_balance": 0,
"created_at": "2026-07-31T20:33:08.922Z"
},
"status_url": "/v1/identity/0fbdbe8c-4895-4a9e-88e4-ae8f852c67a9"
}
Poll until it is usable
certen identity get 0fbdbe8c-4895-4a9e-88e4-ae8f852c67a9
Wait for status: "active". Typically 20–60 seconds. If status reaches failed,
error_message says why.
Do not treat can_sign as readiness. It reports whether the gateway holds key material for this
identity — for an external-signing identity, simply whether a public_key was supplied. It is
true from the moment the identity row is created, including while the ADI does not yet exist on
chain and including when provisioning has stalled. It answers "is a key on file", not "can this
identity sign".
status is the field that tells you whether provisioning finished. If you want proof the identity
is genuinely usable, query the key page directly:
curl -s -X POST https://kermit.accumulatenetwork.io/v3 -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":1,"method":"query","params":{"scope":"acc://my-company.acme/book/1"}}'
That returns the on-chain key page and the key hashes on it — the only answer that cannot be wrong.
4. Check Your Portfolio
View all identities and their multi-chain balances at a glance.
curl https://gateway.kompendium.co/v1/portfolio \
-H "X-API-Key: $API_KEY"
5. Execute a Transaction
Transactions follow a prepare-sign-submit lifecycle. The CLI does all three in one command:
certen tx create --identity <uuid> --to-chain ethereum-sepolia \
--to 0xRecipient --amount 1000000000000000 --sign-with dev
The three steps below are the same flow over HTTP, for when the signer is an HSM, an air-gapped machine, or your own policy engine.
Step 1: Prepare
curl -X POST https://gateway.kompendium.co/v1/transaction \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"identity_id": "your-identity-uuid",
"intent": {
"type": "sendTokens",
"to": "acc://recipient.acme/tokens",
"amount": 100
},
"proof_class": "standard"
}'
Response:
{
"intent_id": "uuid",
"status": "signing_required",
"signing_data": {
"request_id": "uuid",
"transaction_hash": "abcdef...",
"hash_to_sign": "123456..."
}
}
Step 2: Sign hash_to_sign
certen keys sign --name dev --hash 123456...
# Output: signature (128 hex)
This sends nothing anywhere — it prints a signature. It is also the air-gapped path: carry the hash to the machine holding the key, carry the signature back.
Signing without the CLI? Sign the raw BYTES of hash_to_sign. Do not hash it again, and do not
sign the ASCII of the hex string. All three mistakes produce a well-formed 128-hex signature that the
gateway rejects with an error naming none of them.
Note the field name: a new intent returns the bytes as signing_data.hash_to_sign, while co-signing
something that already exists (POST /v1/sign) returns them as signing_data.data_for_signature.
Same contract, different name.
Step 3: Submit the Signature
curl -X POST https://gateway.kompendium.co/v1/transaction/{intent_id}/signature \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"signature": "signature_hex_from_step_2",
"public_key": "ed25519_public_key_hex"
}'
Response:
{
"intent_id": "uuid",
"status": "submitted",
"tx_hash": "abcdef..."
}
6. Check Transaction Status / Get Proof
# Get transaction details (includes proof when available)
curl https://gateway.kompendium.co/v1/transaction/{intent_id} \
-H "X-API-Key: $API_KEY"
# Get proof by ID
curl https://gateway.kompendium.co/v1/proof/{proof_id} \
-H "X-API-Key: $API_KEY"
# Get proof by transaction hash
curl https://gateway.kompendium.co/v1/proof/tx/{tx_hash} \
-H "X-API-Key: $API_KEY"
7. List Pending Actions
View pending multi-sig approvals and governance actions awaiting your signature.
# List all pending actions
curl "https://gateway.kompendium.co/v1/pending" \
-H "X-API-Key: $API_KEY"
# Filter by identity and category
curl "https://gateway.kompendium.co/v1/pending?identity=acc://my-company.acme&category=governance&limit=20" \
-H "X-API-Key: $API_KEY"
Response:
{
"actions": [
{
"id": "uuid",
"identity_url": "acc://my-company.acme",
"category": "governance",
"type": "updateKeyPage",
"status": "eligible",
"tx_hash": "abcdef...",
"collected_signatures": 1,
"total_authorities": 2,
"user_has_signed": false,
"discovered_at": "2025-01-01T00:00:00Z"
}
],
"stats": { "total": 5, "urgent": 1, "governance": 2, "transactions": 3, "awaiting_others": 1 },
"pagination": { "limit": 100, "offset": 0, "total": 5 }
}
8. Sign a Pending Action
Signing a pending action is a two-step process: prepare the signing data, then submit the signature.
Step 1: Create a Sign Request
curl -X POST https://gateway.kompendium.co/v1/sign \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "pending_action",
"target_id": "pending-action-uuid",
"vote": "approve"
}'
Response:
{
"sign_request_id": "uuid",
"status": "signing_required",
"signing_data": {
"data_for_signature": "hex...",
"transaction_hash": "hex...",
"signer_url": "acc://my-company.acme/book/1",
"signer_version": 1,
"timestamp": 1234567890
},
"submit_url": "/v1/sign/{sign_request_id}/signature"
}
Step 2: Submit the Signature
curl -X POST https://gateway.kompendium.co/v1/sign/{sign_request_id}/signature \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"signature": "signature_hex",
"public_key": "public_key_hex"
}'
9. Governance Operations
Modify key pages (add/remove keys, delegates, thresholds) or account authorities.
Prepare a Keypage Update
curl -X POST https://gateway.kompendium.co/v1/governance \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"identity": "acc://my-company.acme",
"operations": [
{ "type": "add_delegate", "delegate_url": "acc://partner.acme/book" },
{ "type": "set_threshold", "threshold": 2 }
]
}'
Response:
{
"governance_op_id": "uuid",
"status": "signing_required",
"signing_data": {
"request_id": "uuid",
"transaction_hash": "hex...",
"hash_to_sign": "hex...",
"key_page_version": 1
},
"submit_url": "/v1/governance/{governance_op_id}/signature"
}
Submit the Governance Signature
curl -X POST https://gateway.kompendium.co/v1/governance/{governance_op_id}/signature \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"signature": "signature_hex",
"public_key": "public_key_hex"
}'
Check Governance Operation Status
curl https://gateway.kompendium.co/v1/governance/{governance_op_id} \
-H "X-API-Key: $API_KEY"
Supported Governance Operations
| Type | Description | Required Field |
|---|---|---|
add_delegate |
Add a delegate authority | delegate_url |
remove_delegate |
Remove a delegate authority | delegate_url |
set_threshold |
Set signature threshold | threshold |
add_key |
Add a key to key page | public_key_hash |
remove_key |
Remove a key from key page | public_key_hash |
add_authority |
Add an authority to an account | authority_url |
remove_authority |
Remove an authority from an account | authority_url |
Note: Keypage operations (
add_delegate,remove_delegate,set_threshold,add_key,remove_key) and authority operations (add_authority,remove_authority) cannot be mixed in a single request.