API docs

pact — the contract layer

mount /pact · base https://zpe.vc/pact · v1.0.0 · 5 operations · 3 write · 0 need no account · beta

archived: committed 2026-10-27, from ec2256dd. Contract: https://zpe.vc/pact/_/api/v1/openapi.json

POST /_/api/v1/pacts Write a pact and freeze its first version, once per idempotency key. postPacts

Write a pact and freeze its first version, once per idempotency key.

Parameters

nameinrequiredtypenotes
Idempotency-KeyheadernostringThe caller's own retry handle. The same key written twice returns the pact the first call made and writes nothing; the body's `idempotencyKey` is the same field for a client that cannot set a header.

Request body

None: this operation takes its arguments in the path and the query.

Responses

statusmeaningbody
200A replay: this account already held a pact written under this idempotency key, and it is answered as it stands. Nothing was written.object
201A pact this account did not hold. Its version 1 is frozen in the same batch as the header, so a 201 always names text that exists.object
400The request is missing a field a pact cannot be written without: the terms, a counterparty, a non-empty due date on a money obligation, or an id this service serves. The sentence names which.object
401Nobody was named: no session cookie and no key. A pact with no account is a row no one owns, so nothing is written.object
403This account may not do thatobject
404Nothing is hereobject
429Too many requestsobject

Example

Write a pact and freeze its first version, once per idempotency key., with a token from the door.

POST /_/api/v1/pacts
curl -X POST 'https://zpe.vc/pact/_/api/v1/pacts' \
  -H 'Authorization: Bearer $ZPE_TOKEN'
200 application/json
{
  "created": false,
  "pact": {},
  "version": {},
  "parties": [
    {}
  ],
  "obligations": [
    {}
  ]
}

The example is generated from the schema in the contract: the shape is the document's, the values are placeholders.

GET /_/api/v1/pacts/{id} One pact at its current version: the terms, the parties, and that version's obligations. getPactsById

One pact at its current version: the terms, the parties, and that version's obligations.

Parameters

nameinrequiredtypenotes
idpathyesstringthe pact to read, as `pact.id` spells it

Request body

None: this operation takes its arguments in the path and the query.

Responses

statusmeaningbody
200The pact as it now stands. `current_version` is derived from the highest version present, so it is the text a reader would sign next.object
400The request could not be readobject
401Nobody was named, so there is no account whose pacts could be read.object
403This account may not do thatobject
404No pact in this account holds that id. Another account's pact reads the same way on purpose: a pact this account cannot read is a pact it must not learn exists.object
429Too many requestsobject

Example

One pact at its current version: the terms, the parties, and that version's obligations., with a token from the door.

GET /_/api/v1/pacts/{id}
curl -X GET 'https://zpe.vc/pact/_/api/v1/pacts/string' \
  -H 'Authorization: Bearer $ZPE_TOKEN'
200 application/json
{
  "current_version": 0,
  "pact": {},
  "version": {},
  "parties": [
    {}
  ],
  "obligations": [
    {}
  ]
}

The example is generated from the schema in the contract: the shape is the document's, the values are placeholders.

POST /_/api/v1/pacts/{id}/sign Sign the version you were shown, as the party you are. postPactsByIdSign

Sign the version you were shown, as the party you are.

Parameters

nameinrequiredtypenotes
idpathyesstringthe pact to sign, as `pact.id` spells it

Request body

None: this operation takes its arguments in the path and the query.

Responses

statusmeaningbody
201One signature row and its evidence record. The row is keyed by pact, version and party, so a second mark from one party on one version is a 409 rather than a second row.object
400The request does not carry what a signature must record: a version, one of the five methods, the consent text's version, a user agent, and a session to have come through.object
401Nobody was named, or the caller is a key. A signature is made by a person, and a key names an account (FR-021).object
403The caller is not a party to this pact, or is the party that wrote it: nobody signs the terms they wrote.object
404No pact in this account holds that id.object
409That party already signed that version, or the version the caller was shown is no longer current. Both are a conflict with a row that exists, and neither writes anything.object
429Too many requestsobject

Example

Sign the version you were shown, as the party you are., with a token from the door.

POST /_/api/v1/pacts/{id}/sign
curl -X POST 'https://zpe.vc/pact/_/api/v1/pacts/string/sign' \
  -H 'Authorization: Bearer $ZPE_TOKEN'
201 application/json
{
  "signature": {},
  "evidence": {}
}

The example is generated from the schema in the contract: the shape is the document's, the values are placeholders.

GET /_/api/v1/pacts/{id}/evidence Everything a stranger needs to check one pact, and the sentences that say what it does not prove. getPactsByIdEvidence

Everything a stranger needs to check one pact, and the sentences that say what it does not prove.

Parameters

nameinrequiredtypenotes
idpathyesstringthe pact to prove, as `pact.id` spells it

Request body

None: this operation takes its arguments in the path and the query.

Responses

statusmeaningbody
200Every version with its hash, the parties, the obligations, the signatures with their tiers, the renditions with their digests, the one history, and the tier the weakest current signature supports.object
400The request could not be readobject
401Nobody was named, so there is no account whose bundle could be read.object
403This account may not do thatobject
404No pact in this account holds that id. An empty bundle would read as "nothing was agreed", which is a worse answer than "not here".object
429Too many requestsobject

Example

Everything a stranger needs to check one pact, and the sentences that say what it does not prove., with a token from the door.

GET /_/api/v1/pacts/{id}/evidence
curl -X GET 'https://zpe.vc/pact/_/api/v1/pacts/string/evidence' \
  -H 'Authorization: Bearer $ZPE_TOKEN'
200 application/json
{
  "schema": "pact.evidence/1",
  "pact": {},
  "current_version": 0,
  "versions": [
    {}
  ],
  "signatures": [
    {}
  ],
  "renditions": [
    {}
  ],
  "events": [
    {}
  ],
  "tier": "L0",
  "claims": {}
}

The example is generated from the schema in the contract: the shape is the document's, the values are placeholders.

POST /_/api/v1/pacts/{id}/invite Mint one link that lets the person it is sent to read this pact and sign it, with no account. postPactsByIdInvite

Mint one link that lets the person it is sent to read this pact and sign it, with no account.

Parameters

nameinrequiredtypenotes
idpathyesstring

Request body

None: this operation takes its arguments in the path and the query.

Responses

statusmeaningbody
201A link naming the seat it signs. The token in it exists in this response and nowhere else: it is stored only as a sha256, so a link cannot be re-read or re-sent later.object
400The request could not be readobject
401The credential is missing or does not open this accountobject
403This account may not do thatobject
404No pact with that id for this caller, or no seat a link may sign: the issuer's seat is refused, and a pact with no counterparty has nobody to send a link to.object
429Too many requestsobject

Example

Mint one link that lets the person it is sent to read this pact and sign it, with no account., with a token from the door.

POST /_/api/v1/pacts/{id}/invite
curl -X POST 'https://zpe.vc/pact/_/api/v1/pacts/string/invite' \
  -H 'Authorization: Bearer $ZPE_TOKEN'
201 application/json
{
  "url": "string",
  "partyId": "string",
  "expiresAt": "2026-10-31T09:00:00Z"
}

The example is generated from the schema in the contract: the shape is the document's, the values are placeholders.