Skip to content
ArchiveZaunEkko Docs
Reading
Text size
Fonts
简体中文English
Show contents

Implementing your service

Status
Current
Updated
2026-09-13
Scope
API Platform provider implementation and conformance checks

Your service exposes four endpoints. The platform calls them; you return an envelope with a fixed shape.

This page covers how to implement them, and what the platform checks once you submit a connection.

Four endpoints

GET  /health/live          the process is alive
GET  /health/ready         your own configuration and dependencies are usable
POST /v1/executions        run one call
POST /v1/reconciliations   look up what actually happened to a call

Health endpoints require no credential. The other two must verify the Authorization: Bearer credential the platform sends. That credential belongs to your connection alone — leaking it opens your execution endpoint to anyone.

Readiness reports on your availability. Do not probe the platform from it: when the platform is unavailable you neither need to nor should report yourself unready.

Execution

POST /v1/executions
Authorization: Bearer <credential the platform configured for you>
Idempotency-Key: <stable identifier generated by the platform>
Content-Type: application/json
{ "payload": { "fields you defined in your listing contract": "value" } }

payload is a non-empty JSON object whose contents your listing contract defines. The envelope itself has exactly this one top-level field, and any unknown top-level field must be rejected.

Response envelope

Success or failure, the shape is the same:

{
  "outcome": "SUCCEEDED",
  "correlationId": "your own job id",
  "result": { "businessResult": true },
  "errorCode": "",
  "httpStatus": 0
}

Omit fields that do not apply. Four outcomes, and the HTTP status must match:

outcomeHTTP statusMeaningWhat the platform does
SUCCEEDEDany 2xxBusiness done and result persistedSettles and charges
DEFINED_FAILUREthe same 4xx/5xx as httpStatusThe request definitively failedReleases the hold, no charge
RETRYABLE_BEFORE_ACCEPTexactly 503You can prove the call was not acceptedBounded redispatch
UNKNOWN_OUTCOMEexactly 202Possibly accepted, outcome undeterminedReconciles only, never resends

DEFINED_FAILURE needs a stable errorCode (64 characters or fewer).

Do not use DEFINED_FAILURE for infrastructure uncertainty. It means "this request definitively failed", and the platform releases the hold on that basis. If you had in fact already executed the work, that work goes unpaid. When uncertain, use UNKNOWN_OUTCOME.

Timeouts, dropped connections, malformed JSON, oversized bodies, status/outcome mismatches, redirects — the platform treats all of them as UNKNOWN_OUTCOME. So anything you have accepted must be discoverable through reconciliation.

Idempotency

Every call carries a stable Idempotency-Key. You need to:

  1. Fingerprint the raw payload bytes and store that fingerprint against the key;
  2. On same key, same fingerprint, return the stored outcome without re-executing;
  3. On same key, different fingerprint, return DEFINED_FAILURE with both httpStatus and the HTTP status set to 409, and leave the original record unchanged.

Storage must be durable. After a restart, reconciliation for the same key must still return what you accepted — an empty in-memory map is not evidence that nothing was accepted.

Order matters too: persist the "accepted" marker before the business side effect (or within the same atomic operation), persist the final outcome before responding, and write the HTTP response only after the transaction commits.

Reconciliation

POST /v1/reconciliations
{ "providerIdempotencyKey": "the key the platform used earlier" }

Reconciliation never starts execution. It only reads what you already stored.

Returning success for a key you cannot find is the most dangerous implementation. It claims work that never happened, and the platform charges the caller for it.

What the platform checks after you submit

Once a connection is submitted, the platform calls your endpoints and runs a contract conformance check. Results appear directly on your connection page, and you can re-run it yourself as often as you like — fix, re-run, see what is still red, without waiting on anyone.

The check produces one real call against your service. It uses a different Idempotency-Key prefix from live traffic (ekko-conformance:) so you can recognise it; that call creates no receipt and holds or charges nothing.

The check does not understand your business: it sends a deliberately meaningless payload, and treats SUCCEEDED and DEFINED_FAILURE as equally acceptable. It verifies envelope shape, idempotency semantics, and credential enforcement — not business success. Rejecting junk input cleanly with a DEFINED_FAILURE and an errorCode is itself proof of compliance.

The nine checks

CheckFailing means
Liveness/health/live unreachable or not 2xx
Readiness/health/ready unreachable or not 2xx. Remember it must not depend on the platform
Execution requires credentialYour execution endpoint answers without a credential. Anyone can drive your business logic
Execution envelope validThe outcome is not one of the four, or the HTTP status does not match it
Replay is stableSame key and payload returned a different result, so the work ran twice
Fingerprint conflictSame key with a different payload was not rejected with 409, so your idempotency record is not actually bound to the payload
Unknown envelope field rejectedYou accepted a top-level field outside the contract. When the protocol evolves you will swallow new fields without understanding them
Known key reconcilesA key you just accepted cannot be found, or returns RETRYABLE_BEFORE_ACCEPT — the latter makes the platform execute it again
Unknown key does not claim successReconciling a never-submitted key returned SUCCEEDED

About "skipped"

A check shown as skipped is neither passed nor failed — it means no evidence was gathered.

If the execution endpoint itself did not work, the three idempotency checks have no baseline to compare against and are all skipped. Do not go auditing your idempotency implementation at that point: fix the earlier failure first, then re-run to get a real verdict on those.

How the check relates to publication

Passing the technical check is a precondition for approval. A connection that has not passed will not be approved.

Changing the connection's address or code invalidates earlier results; re-run the check.

Passing is not the same as being listed. It only says the technical contract holds; whether a listing belongs in the catalog is a separate business judgement.

A minimal skeleton

Pseudocode for ordering; any language works:

POST /v1/executions:
  verify Authorization, otherwise → 401
  parse envelope, unknown top-level field → 400
  fingerprint = hash of raw payload bytes

  begin transaction
    record = read by key, locked
    if record exists:
        if record.fingerprint != fingerprint → 409 DEFINED_FAILURE
        else → return the stored outcome        // do not re-execute
    else:
        write the "accepted" marker (key, fingerprint)
  commit

  run the business logic
  persist the final outcome and correlationId
  respond

Reconciliation is a read by key and nothing else — no writes at all.

What the check does not cover

The check verifies envelope shape, idempotency semantics, and credential enforcement. Failure paths such as retries, timeouts, and oversized results cannot be triggered from outside, so they are not covered — nine green items do not mean those paths are correct. They are contract requirements all the same, and remain yours to satisfy.

There is no offline version of the conformance check; trigger it from the connection page once your connection is submitted.

Where the protocol and this page disagree, trust the platform's actual API behaviour. For the onboarding path see Becoming a provider; for current gaps see Current limitations.