For the complete documentation index, see llms.txt. This page is also available as Markdown.

Trade Trust Credentials

Issue and verify a verifiable credential through core-engine.

Complete a signed credential

post

Hand back the signed credential from the matching prepare call and get the finished one.

Authorizations
X-API-KeystringRequired

AWS API Gateway key, required only on the api-sandbox and api-v2 servers. It is checked by the gateway, before the request reaches this service, so it does not substitute for the bearer token - those two headers are read by different layers. Omit it when port-forwarding to a pod.

AuthorizationstringRequired

OAuth2 bearer token from the shared BaaS auth server.

Every endpoint in this subset requires one. Note the security filter runs BEFORE routing, so an unauthenticated request to a path that does not exist also answers 401, not 404 - a 404 is only visible to an authenticated caller.

Body

Request for POST /tradetrust/credentials/complete — hand back the signed credential from the matching prepare call and get the finished one.

preparationId is single-use and expires (core-engine's pending store has a ~15 minute TTL); a stale one is a 404, mapped by CustomExceptionHandler's generic core-engine bucket.

preparationIdstring · min: 1Required
Responses
200

OK

*/*

Standard BaaS response envelope. Mirrors the shape used across the microservices so callers get a consistent contract on L2 as on L1.

successbooleanOptional
errorCodestringOptional
messagestringOptional
post/tradetrust/credentials/complete
POST /z2/tradetrust/credentials/complete HTTP/1.1
Host: api-sandbox.zetrix.com
X-API-Key: YOUR_API_KEY
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 92

{
  "preparationId": "text",
  "signedVerifiableCredential": {
    "ANY_ADDITIONAL_PROPERTY": "anything"
  }
}
200

OK

{
  "success": true,
  "errorCode": "text",
  "message": "text",
  "data": {
    "verifiableCredential": {
      "ANY_ADDITIONAL_PROPERTY": "anything"
    }
  }
}

Issue a credential in one call

post

Issue a credential in one call: prepare -> core-engine signs -> complete. Sends the issuer's private key to core-engine — see this class's javadoc.

Authorizations
X-API-KeystringRequired

AWS API Gateway key, required only on the api-sandbox and api-v2 servers. It is checked by the gateway, before the request reaches this service, so it does not substitute for the bearer token - those two headers are read by different layers. Omit it when port-forwarding to a pod.

AuthorizationstringRequired

OAuth2 bearer token from the shared BaaS auth server.

Every endpoint in this subset requires one. Note the security filter runs BEFORE routing, so an unauthenticated request to a path that does not exist also answers 401, not 404 - a 404 is only visible to an authenticated caller.

Body

Request for POST /tradetrust/credentials/issue — the same build as {@link PrepareCredentialReqDto PrepareCredentialReqDto}, plus the issuer's key pair for delegated signing (BT-2620's chosen signing model: prepare -> core-engine's /credentials/sign -> complete, in one call).

This sends the issuer's private key to core-engine. See {@link MultikeyDto MultikeyDto} and the SDK's signRemote javadoc for the custody note.

issuerDidstring · min: 1Required
typestring[]Optional
contextstring[]Optional
validFromstringOptional
expirationDatestringOptional
statusPurposestringOptionalPattern: (?i)^(revocation|suspension)$
Responses
200

OK

*/*

Standard BaaS response envelope. Mirrors the shape used across the microservices so callers get a consistent contract on L2 as on L1.

successbooleanOptional
errorCodestringOptional
messagestringOptional
post/tradetrust/credentials/issue
POST /z2/tradetrust/credentials/issue HTTP/1.1
Host: api-sandbox.zetrix.com
X-API-Key: YOUR_API_KEY
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 414

{
  "issuerDid": "text",
  "credentialSubject": {
    "ANY_ADDITIONAL_PROPERTY": "anything"
  },
  "type": [
    "text"
  ],
  "context": [
    "text"
  ],
  "validFrom": "text",
  "expirationDate": "text",
  "statusPurpose": "text",
  "renderMethod": {
    "ANY_ADDITIONAL_PROPERTY": "anything"
  },
  "qrCode": {
    "ANY_ADDITIONAL_PROPERTY": "anything"
  },
  "keyPair": {
    "id": "text",
    "type": "text",
    "controller": "text",
    "publicKeyMultibase": "text",
    "secretKeyMultibase": "text",
    "@context": "text"
  }
}
200

OK

{
  "success": true,
  "errorCode": "text",
  "message": "text",
  "data": {
    "verifiableCredential": {
      "ANY_ADDITIONAL_PROPERTY": "anything"
    }
  }
}

Prepare a credential for signing

post

Build the unsigned credential and the spec for signing it. The caller signs, then calls complete.

Authorizations
X-API-KeystringRequired

AWS API Gateway key, required only on the api-sandbox and api-v2 servers. It is checked by the gateway, before the request reaches this service, so it does not substitute for the bearer token - those two headers are read by different layers. Omit it when port-forwarding to a pod.

AuthorizationstringRequired

OAuth2 bearer token from the shared BaaS auth server.

Every endpoint in this subset requires one. Note the security filter runs BEFORE routing, so an unauthenticated request to a path that does not exist also answers 401, not 404 - a 404 is only visible to an authenticated caller.

Body

Request for POST /tradetrust/credentials/prepare — build the unsigned credential and the spec for signing it. issuerDid and credentialSubject are required; everything else defaults server-side in core-engine.

statusPurpose attaches a status-list entry, which is what later makes the credential revocable; a plain string here (not the SDK's own enum) so this DTO — and the OpenAPI document generated from it — stays independent of the SDK's type, per BT-2620's design.

issuerDidstring · min: 1Required
typestring[]Optional
contextstring[]Optional
validFromstringOptional
expirationDatestringOptional
statusPurposestringOptionalPattern: (?i)^(revocation|suspension)$
Responses
200

OK

*/*

Standard BaaS response envelope. Mirrors the shape used across the microservices so callers get a consistent contract on L2 as on L1.

successbooleanOptional
errorCodestringOptional
messagestringOptional
post/tradetrust/credentials/prepare
POST /z2/tradetrust/credentials/prepare HTTP/1.1
Host: api-sandbox.zetrix.com
X-API-Key: YOUR_API_KEY
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 282

{
  "issuerDid": "text",
  "credentialSubject": {
    "ANY_ADDITIONAL_PROPERTY": "anything"
  },
  "type": [
    "text"
  ],
  "context": [
    "text"
  ],
  "validFrom": "text",
  "expirationDate": "text",
  "statusPurpose": "text",
  "renderMethod": {
    "ANY_ADDITIONAL_PROPERTY": "anything"
  },
  "qrCode": {
    "ANY_ADDITIONAL_PROPERTY": "anything"
  }
}
200

OK

{
  "success": true,
  "errorCode": "text",
  "message": "text",
  "data": {
    "preparationId": "text",
    "unsignedVerifiableCredential": {
      "ANY_ADDITIONAL_PROPERTY": "anything"
    },
    "signingSpec": {
      "mandatoryPointers": [
        "text"
      ],
      "cryptoSuite": "text",
      "expectedIssuerDid": "text"
    }
  }
}

Revoke or suspend a credential

post

Revoke, un-revoke or suspend one credential — revoked chooses the direction and purpose chooses the list, so this one route covers all four.

The caller signs the mutation; this service only forwards it and never handles issuer key material. See {@link RevokeCredentialReqDto RevokeCredentialReqDto} for the exact string to sign.

Authorizations
X-API-KeystringRequired

AWS API Gateway key, required only on the api-sandbox and api-v2 servers. It is checked by the gateway, before the request reaches this service, so it does not substitute for the bearer token - those two headers are read by different layers. Omit it when port-forwarding to a pod.

AuthorizationstringRequired

OAuth2 bearer token from the shared BaaS auth server.

Every endpoint in this subset requires one. Note the security filter runs BEFORE routing, so an unauthenticated request to a path that does not exist also answers 401, not 404 - a 404 is only visible to an authenticated caller.

Body

Request for POST /tradetrust/credentials/revoke — flip one status-list bit, authorized by the issuer's own signature.

This service cannot revoke on your behalf, by design. core-engine only ever verifies a status mutation, never signs one, so the authorization has to come from whoever holds the issuer key. This route is a pass-through: it carries nonce, timestamp and signature to core-engine and touches no key material at all — unlike /credentials/issue, no {@link MultikeyDto MultikeyDto} appears here and none may ever be added.

Sign this exact string with the issuer's P-256 key, SHA-256 prehashed, as a 64-byte compact r‖s pair, hex-encoded:

STATUS-MUTATE|{issuerDid}|{purpose}|{index}|{revoked}|{nonce}|{timestamp}

The Java SDK's CredentialsClient.statusMutationMessage(...) builds it, and Signatures.derToCompactRs converts a JCA signature to the wire form — SHA256withECDSA already prehashes and emits DER, and both mistakes yield a well-formed signature that fails with only "signature invalid" to go on.

One route covers all four operations. revoked chooses the direction, purpose chooses the list: revocation + true revokes, revocation + false un-revokes, and suspension does the same to the suspension list. revoked is boxed and required so an omitted field is a 400 rather than a silent un-revoke.

Two server-side rules make a naive retry fail. timestamp must be within ~60s of core-engine's clock, and it must be strictly newer than the last accepted mutation for this index — so a retry has to be re-signed with a fresh timestamp, never replayed.

issuerDidstring · min: 1Required
purposestring · min: 1Required

Which list to write to. Same two values prepare's statusPurpose accepts.

Pattern: (?i)^(revocation|suspension)$
indexinteger · int32Required

The credential's own credentialStatus.statusListIndex. Read it off the credential rather than guessing: an unallocated index can be written, and a credential later issued into it would be born revoked.

revokedbooleanRequired
noncestring · min: 1Required

Any unique value; it is signed, so it cannot be swapped after the fact.

timestampstring · min: 1Required

ISO-8601, and part of the signed message — not a header this service adds.

signaturestring · min: 1Required

Hex-encoded 64-byte compact r‖s P-256 signature over the canonical message above.

Responses
200

OK

*/*

Standard BaaS response envelope. Mirrors the shape used across the microservices so callers get a consistent contract on L2 as on L1.

successbooleanOptional
errorCodestringOptional
messagestringOptional
post/tradetrust/credentials/revoke
POST /z2/tradetrust/credentials/revoke HTTP/1.1
Host: api-sandbox.zetrix.com
X-API-Key: YOUR_API_KEY
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 115

{
  "issuerDid": "text",
  "purpose": "text",
  "index": 1,
  "revoked": true,
  "nonce": "text",
  "timestamp": "text",
  "signature": "text"
}
200

OK

{
  "success": true,
  "errorCode": "text",
  "message": "text",
  "data": {
    "issuerId": "text",
    "purpose": "text",
    "index": 1,
    "revoked": true
  }
}

Sign a prepared credential

post

Have core-engine sign a prepared credential without completing it — the middle step of prepare -> sign -> complete, for callers who want to see the unsigned document first. Sends the issuer's private key to core-engine, like issue.

Authorizations
X-API-KeystringRequired

AWS API Gateway key, required only on the api-sandbox and api-v2 servers. It is checked by the gateway, before the request reaches this service, so it does not substitute for the bearer token - those two headers are read by different layers. Omit it when port-forwarding to a pod.

AuthorizationstringRequired

OAuth2 bearer token from the shared BaaS auth server.

Every endpoint in this subset requires one. Note the security filter runs BEFORE routing, so an unauthenticated request to a path that does not exist also answers 401, not 404 - a 404 is only visible to an authenticated caller.

Body

Request for POST /tradetrust/credentials/sign — have core-engine apply the issuer's key to a credential built by an earlier prepare, without completing it.

This is the middle step of prepare -> sign -> complete, exposed on its own. /credentials/issue already runs all three in one call; the reason to take them separately is to see the unsigned document (and its signingSpec) before anything is signed, and to keep the complete call under your own control. The result still has to go to complete — signing alone does not produce a finished credential.

This sends the issuer's private key to core-engine, exactly as issue does — see {@link MultikeyDto MultikeyDto}. If that is not acceptable, do not use this route: sign the document from prepare yourself and call complete directly. That path exists precisely so key custody can stay on your side.

Requires ALLOW_ISSUER_SIGNING=true on core-engine, which defaults to off. Where it is off this route answers 400 no matter how well-formed the request is — the same condition that gates issue and ebl/mint.

preparationId is single-use and expires (~15 minutes), and keyPair.controller must equal the issuerDid the preparation was created for; core-engine rejects a mismatch rather than signing with the wrong identity.

preparationIdstring · min: 1Required
Responses
200

OK

*/*

Standard BaaS response envelope. Mirrors the shape used across the microservices so callers get a consistent contract on L2 as on L1.

successbooleanOptional
errorCodestringOptional
messagestringOptional
post/tradetrust/credentials/sign
POST /z2/tradetrust/credentials/sign HTTP/1.1
Host: api-sandbox.zetrix.com
X-API-Key: YOUR_API_KEY
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 156

{
  "preparationId": "text",
  "keyPair": {
    "id": "text",
    "type": "text",
    "controller": "text",
    "publicKeyMultibase": "text",
    "secretKeyMultibase": "text",
    "@context": "text"
  }
}
200

OK

{
  "success": true,
  "errorCode": "text",
  "message": "text",
  "data": {
    "signedVerifiableCredential": {
      "ANY_ADDITIONAL_PROPERTY": "anything"
    }
  }
}

Get the status list

get

The signed Bitstring Status List credential for one issuer and purpose — the whole list, not one credential's state. To check a single credential use /verify, which resolves revocation itself.

Authorizations
X-API-KeystringRequired

AWS API Gateway key, required only on the api-sandbox and api-v2 servers. It is checked by the gateway, before the request reaches this service, so it does not substitute for the bearer token - those two headers are read by different layers. Omit it when port-forwarding to a pod.

AuthorizationstringRequired

OAuth2 bearer token from the shared BaaS auth server.

Every endpoint in this subset requires one. Note the security filter runs BEFORE routing, so an unauthenticated request to a path that does not exist also answers 401, not 404 - a 404 is only visible to an authenticated caller.

Path parameters
issuerDidstringRequired
purposestringRequired
Responses
200

OK

*/*

Standard BaaS response envelope. Mirrors the shape used across the microservices so callers get a consistent contract on L2 as on L1.

successbooleanOptional
errorCodestringOptional
messagestringOptional
get/tradetrust/credentials/status/{issuerDid}/{purpose}
GET /z2/tradetrust/credentials/status/{issuerDid}/{purpose} HTTP/1.1
Host: api-sandbox.zetrix.com
X-API-Key: YOUR_API_KEY
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
200

OK

{
  "success": true,
  "errorCode": "text",
  "message": "text",
  "data": {
    "statusListCredential": {
      "ANY_ADDITIONAL_PROPERTY": "anything"
    }
  }
}

Verify a credential

post

Check signature, issuer binding and (if declared) revocation. Read the response's valid AND trusted fields — never valid alone.

Authorizations
X-API-KeystringRequired

AWS API Gateway key, required only on the api-sandbox and api-v2 servers. It is checked by the gateway, before the request reaches this service, so it does not substitute for the bearer token - those two headers are read by different layers. Omit it when port-forwarding to a pod.

AuthorizationstringRequired

OAuth2 bearer token from the shared BaaS auth server.

Every endpoint in this subset requires one. Note the security filter runs BEFORE routing, so an unauthenticated request to a path that does not exist also answers 401, not 404 - a 404 is only visible to an authenticated caller.

Body

Request for POST /tradetrust/credentials/verify — check signature, issuer binding and (if declared) revocation. Open on core-engine's side, but this service still requires its own caller auth like every other route (no addition to SecurityConfig.PUBLIC_PATHS).

trustedIssuers is optional; when supplied, the response's trusted field reports whether the credential's issuer is on it.

trustedIssuersstring[]Optional
Responses
200

OK

*/*

Standard BaaS response envelope. Mirrors the shape used across the microservices so callers get a consistent contract on L2 as on L1.

successbooleanOptional
errorCodestringOptional
messagestringOptional
post/tradetrust/credentials/verify
POST /z2/tradetrust/credentials/verify HTTP/1.1
Host: api-sandbox.zetrix.com
X-API-Key: YOUR_API_KEY
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 89

{
  "verifiableCredential": {
    "ANY_ADDITIONAL_PROPERTY": "anything"
  },
  "trustedIssuers": [
    "text"
  ]
}
200

OK

{
  "success": true,
  "errorCode": "text",
  "message": "text",
  "data": {
    "valid": true,
    "issuer": "text",
    "trusted": true,
    "status": "ACTIVE",
    "checks": [
      {
        "type": "text",
        "status": "text",
        "reason": "text"
      }
    ]
  }
}

Last updated