Credentials API
Enroll node identities, issue and verify credentials, revoke them and manage node tags. Signing keys remain on the server.
Operations
listCredentials
GET /api/v2/credentials
Requires: invoke role
Credentials issued in the namespace, newest first, filtered by issuer_label, node_label, traverser_id, root_id, subject_id, kind, parent_id and revoked. limit is clamped to 1-1000.
Generated Python client internals: atfgraph._generated.api.credentials_api.CredentialsApi.list_credentials()
Parameters
| Parameter | In | Required | Type |
|---|
issuer_label | query | no | string |
kind | query | no | CredentialKind |
limit | query | no | integer |
node_label | query | no | string |
parent_id | query | no | string |
revoked | query | no | boolean |
root_id | query | no | string |
subject_id | query | no | string |
traverser_id | query | no | string |
Responses
Example response 200
{
"items": [
{
"credential": {
"@context": [
"string"
],
"credentialSubject": {},
"expirationDate": "string",
"id": "string",
"issuanceDate": "string",
"issuer": "string",
"proof": {
"created": {},
"cryptosuite": {},
"proofPurpose": {},
"proofValue": {},
"type": {},
"verificationMethod": {}
},
"type": [
"string"
]
},
"expires_at": 0,
"id": "string",
"issued_at": 0,
"issuer_did": "string",
"issuer_key_id": "string",
"issuer_label": "string",
"kind": "execution",
"node_label": "string",
"parent_id": "string",
"principal": "string",
"revocation_reason": "string",
"revoked_at": 0,
"revoked_by": "string",
"root_id": "string",
"subject_id": "string",
"traverser_id": "string",
"type": "string"
}
]
}
issueCredential
POST /api/v2/credentials
Requires: invoke role, worker role
Issue a W3C VC 1.1 credential signed with the issuer node's enrolled DID (Data Integrity eddsa-jcs-2022). The caller must have registered the issuer node, or be a worker executing it under an active lease (403 issuer_forbidden). execution credentials certify a terminal traverser owned by the caller or inside the worker's leased subtree (409 traverser_active before completion) and are idempotent per issuer key. custom credentials carry the caller's subject (string id, at most 64 KiB) and an alphanumeric type other than VerifiableCredential or AgentTagCredential. 409 did_not_enrolled when the issuer has no active DID.
Generated Python client internals: atfgraph._generated.api.credentials_api.CredentialsApi.issue_credential()
Request body
CredentialIssue (required)
{
"issuer_label": "string"
}
Responses
Example response 201
{
"credential": {
"@context": [
"string"
],
"credentialSubject": {},
"expirationDate": "string",
"id": "string",
"issuanceDate": "string",
"issuer": "string",
"proof": {
"created": "string",
"cryptosuite": "string",
"proofPurpose": "string",
"proofValue": "string",
"type": "string",
"verificationMethod": "string"
},
"type": [
"string"
]
},
"expires_at": 0,
"id": "string",
"issued_at": 0,
"issuer_did": "string",
"issuer_key_id": "string",
"issuer_label": "string",
"kind": "execution",
"node_label": "string",
"parent_id": "string",
"principal": "string",
"revocation_reason": "string",
"revoked_at": 0,
"revoked_by": "string",
"root_id": "string",
"subject_id": "string",
"traverser_id": "string",
"type": "string"
}
listDids
GET /api/v2/credentials/dids
Requires: invoke role
Every enrolled DID in the namespace with its current key state, ordered by label.
Generated Python client internals: atfgraph._generated.api.credentials_api.CredentialsApi.list_dids()
Responses
Example response 200
{
"items": [
{
"algorithm": "string",
"also_known_as": [
"string"
],
"created_at": 0,
"did": "string",
"did_document": {
"@context": [
"string"
],
"alsoKnownAs": [
"string"
],
"assertionMethod": [
"string"
],
"authentication": [
"string"
],
"id": "string",
"verificationMethod": [
{}
]
},
"encryption": "string",
"key_id": "string",
"key_state": "string",
"label": "string",
"master_key_id": "string",
"public_key": "string",
"public_key_multibase": "string",
"verification_method": "string"
}
]
}
enrolDid
POST /api/v2/credentials/dids
Requires: admin role
Enrol a node's active identity key as a standard did:key (Ed25519, multicodec 0xed01), creating the identity when the label has none. The private key copy is stored encrypted (XChaCha20-Poly1305, bound to namespace, key id and DID) under the daemon credential key. Enrolling an already enrolled key returns the existing record. Key lifecycle stays with the identities operations.
Generated Python client internals: atfgraph._generated.api.credentials_api.CredentialsApi.enrol_did()
Request body
DidEnrol (required)
{
"label": "string"
}
Responses
Example response 201
{
"algorithm": "string",
"also_known_as": [
"string"
],
"created_at": 0,
"did": "string",
"did_document": {
"@context": [
"string"
],
"alsoKnownAs": [
"string"
],
"assertionMethod": [
"string"
],
"authentication": [
"string"
],
"id": "string",
"verificationMethod": [
{
"controller": "string",
"id": "string",
"publicKeyJwk": {},
"publicKeyMultibase": "string",
"type": "string"
}
]
},
"encryption": "string",
"key_id": "string",
"key_state": "string",
"label": "string",
"master_key_id": "string",
"public_key": "string",
"public_key_multibase": "string",
"verification_method": "string"
}
resolveDid
POST /api/v2/credentials/dids/resolve
Requires: invoke role
Resolve did:key offline or did:web through bounded HTTPS (no redirects, public addresses only, 5 s, 64 KiB; 422 on failure). local names the enrolled identity when the DID belongs to this namespace.
Generated Python client internals: atfgraph._generated.api.credentials_api.CredentialsApi.resolve_did()
Request body
DidResolve (required)
{
"did": "string"
}
Responses
Example response 200
{
"canonical_did": "string",
"did": "string",
"document": {},
"legacy_encoding": false,
"local": {
"key_id": "string",
"key_state": "string",
"label": "string"
},
"method": "key",
"resolved_from": "string",
"verification_methods": [
{
"id": "string",
"public_key": "string",
"type": "string"
}
]
}
getDid
GET /api/v2/credentials/dids/{label}
Requires: invoke role
The active enrolled DID of one node label. web_base_url (https) adds the did:web alias the root would publish under /agents/{label}/did.json.
Generated Python client internals: atfgraph._generated.api.credentials_api.CredentialsApi.get_did()
Parameters
| Parameter | In | Required | Type |
|---|
label | path | yes | string |
web_base_url | query | no | string |
Responses
Example response 200
{
"algorithm": "string",
"also_known_as": [
"string"
],
"created_at": 0,
"did": "string",
"did_document": {
"@context": [
"string"
],
"alsoKnownAs": [
"string"
],
"assertionMethod": [
"string"
],
"authentication": [
"string"
],
"id": "string",
"verificationMethod": [
{
"controller": "string",
"id": "string",
"publicKeyJwk": {},
"publicKeyMultibase": "string",
"type": "string"
}
]
},
"encryption": "string",
"key_id": "string",
"key_state": "string",
"label": "string",
"master_key_id": "string",
"public_key": "string",
"public_key_multibase": "string",
"verification_method": "string"
}
listTagLedger
GET /api/v2/credentials/tags
Requires: invoke role
The tag approval ledger, optionally filtered by label and state, ordered by label then tag (at most 1000 rows).
Generated Python client internals: atfgraph._generated.api.credentials_api.CredentialsApi.list_tag_ledger()
Parameters
| Parameter | In | Required | Type |
|---|
label | query | no | string |
state | query | no | TagState |
Responses
Example response 200
{
"items": [
{
"decided_at": 0,
"decided_by": "string",
"label": "string",
"proposed_at": 0,
"proposed_by": "string",
"reason": "string",
"state": "pending",
"tag": "string",
"updated_at": 0
}
]
}
proposeTags
POST /api/v2/credentials/tags
Requires: invoke role
Propose tags for a node the caller registered (403 tag_forbidden otherwise). Tags are trimmed, lower-cased `[a-z0-9-_.:]{1,64}` and deduplicated. The namespace policy decides per tag: auto approves immediately, manual records pending, forbidden records rejected. When approvals change, the node's AgentTagCredential is superseded and reissued by the policy issuer if one is enrolled; otherwise warning explains why no credential was issued.
Generated Python client internals: atfgraph._generated.api.credentials_api.CredentialsApi.propose_tags()
Request body
TagProposal (required)
{
"label": "string",
"tags": [
"string"
]
}
Responses
Example response 200
{
"credential": {
"credential": {
"@context": [
"string"
],
"credentialSubject": {},
"expirationDate": "string",
"id": "string",
"issuanceDate": "string",
"issuer": "string",
"proof": {
"created": {},
"cryptosuite": {},
"proofPurpose": {},
"proofValue": {},
"type": {},
"verificationMethod": {}
},
"type": [
"string"
]
},
"expires_at": 0,
"id": "string",
"issued_at": 0,
"issuer_did": "string",
"issuer_key_id": "string",
"issuer_label": "string",
"kind": "execution",
"node_label": "string",
"parent_id": "string",
"principal": "string",
"revocation_reason": "string",
"revoked_at": 0,
"revoked_by": "string",
"root_id": "string",
"subject_id": "string",
"traverser_id": "string",
"type": "string"
},
"label": "string",
"modes": {
"key": "auto"
},
"tags": [
{
"decided_at": 0,
"decided_by": "string",
"label": "string",
"proposed_at": 0,
"proposed_by": "string",
"reason": "string",
"state": "pending",
"tag": "string",
"updated_at": 0
}
],
"warning": "string"
}
decideTags
POST /api/v2/credentials/tags/decide
Requires: admin role
Admin approve, reject or revoke of tags for a node. approve and reject act on pending tags, revoke on approved tags; omit tags to act on every candidate (409 tag_not_pending / already_revoked when there is none). Approvals and revocations refresh the node's AgentTagCredential.
Generated Python client internals: atfgraph._generated.api.credentials_api.CredentialsApi.decide_tags()
Request body
TagDecision (required)
{
"decision": "approve",
"label": "string"
}
Responses
Example response 200
{
"changed": [
"string"
],
"credential": {
"credential": {
"@context": [
"string"
],
"credentialSubject": {},
"expirationDate": "string",
"id": "string",
"issuanceDate": "string",
"issuer": "string",
"proof": {
"created": {},
"cryptosuite": {},
"proofPurpose": {},
"proofValue": {},
"type": {},
"verificationMethod": {}
},
"type": [
"string"
]
},
"expires_at": 0,
"id": "string",
"issued_at": 0,
"issuer_did": "string",
"issuer_key_id": "string",
"issuer_label": "string",
"kind": "execution",
"node_label": "string",
"parent_id": "string",
"principal": "string",
"revocation_reason": "string",
"revoked_at": 0,
"revoked_by": "string",
"root_id": "string",
"subject_id": "string",
"traverser_id": "string",
"type": "string"
},
"decision": "approve",
"label": "string",
"tags": [
{
"decided_at": 0,
"decided_by": "string",
"label": "string",
"proposed_at": 0,
"proposed_by": "string",
"reason": "string",
"state": "pending",
"tag": "string",
"updated_at": 0
}
],
"warning": "string"
}
getTagPolicy
GET /api/v2/credentials/tags/policy
Requires: invoke role
The namespace tag approval policy (default auto with no rules) and who last changed it.
Generated Python client internals: atfgraph._generated.api.credentials_api.CredentialsApi.get_tag_policy()
Responses
Example response 200
{
"default_mode": "auto",
"issuer_label": "string",
"rules": [
{
"approval": "auto",
"reason": "string",
"tags": [
"string"
]
}
],
"updated_at": 0,
"updated_by": "string"
}
putTagPolicy
PUT /api/v2/credentials/tags/policy
Requires: admin role
Replace the namespace tag approval policy: default_mode, at most 64 rules of tags with an approval mode and optional reason, and the issuer_label whose enrolled DID signs tag credentials.
Generated Python client internals: atfgraph._generated.api.credentials_api.CredentialsApi.put_tag_policy()
Request body
TagPolicyPut (required)
{
"default_mode": "auto",
"issuer_label": "string",
"rules": [
{
"approval": "auto",
"tags": [
"string"
]
}
]
}
Responses
Example response 200
{
"default_mode": "auto",
"issuer_label": "string",
"rules": [
{
"approval": "auto",
"reason": "string",
"tags": [
"string"
]
}
],
"updated_at": 0,
"updated_by": "string"
}
verifyCredential
POST /api/v2/credentials/verify
Requires: invoke role, worker role
Verify a presented credential from any issuer: structure, proof type and cryptosuite, proofPurpose, verificationMethod ownership, issuer key resolution (did:key offline; did:web only when resolve_remote is true), signature, issuance/notBefore/expiration at the evaluation time at (5 minute skew). valid reports those checks; trusted additionally requires the credential to be known and unrevoked in this namespace, byte-identical to the issued document, and signed by an enrolled unrevoked key. checks lists every step.
Generated Python client internals: atfgraph._generated.api.credentials_api.CredentialsApi.verify_credential()
Request body
CredentialVerify (required)
{
"credential": {}
}
Responses
Example response 200
{
"checks": [
{
"detail": "string",
"name": "string",
"ok": false
}
],
"credential_id": "string",
"evaluated_at": 0,
"issuer": "string",
"issuer_resolution": "string",
"key_state": "string",
"known": false,
"message": "string",
"reason": "string",
"revoked_at": 0,
"subject_id": "string",
"trusted": false,
"valid": false,
"verification_method": "string"
}
getCredential
GET /api/v2/credentials/{id}
Requires: invoke role, worker role
One issued credential with its signed document. A worker may only read credentials of its execution root (403 credential_forbidden).
Generated Python client internals: atfgraph._generated.api.credentials_api.CredentialsApi.get_credential()
Parameters
| Parameter | In | Required | Type |
|---|
id | path | yes | string |
lease_token | query | no | string |
step_id | query | no | string |
task_id | query | no | string |
Responses
Example response 200
{
"credential": {
"@context": [
"string"
],
"credentialSubject": {},
"expirationDate": "string",
"id": "string",
"issuanceDate": "string",
"issuer": "string",
"proof": {
"created": "string",
"cryptosuite": "string",
"proofPurpose": "string",
"proofValue": "string",
"type": "string",
"verificationMethod": "string"
},
"type": [
"string"
]
},
"expires_at": 0,
"id": "string",
"issued_at": 0,
"issuer_did": "string",
"issuer_key_id": "string",
"issuer_label": "string",
"kind": "execution",
"node_label": "string",
"parent_id": "string",
"principal": "string",
"revocation_reason": "string",
"revoked_at": 0,
"revoked_by": "string",
"root_id": "string",
"subject_id": "string",
"traverser_id": "string",
"type": "string"
}
revokeCredential
POST /api/v2/credentials/{id}/revoke
Requires: invoke role
Revoke an issued credential (idempotent). Allowed for the issuing principal, an owner of the issuer node, or an admin; reason is at most 512 characters.
Generated Python client internals: atfgraph._generated.api.credentials_api.CredentialsApi.revoke_credential()
Parameters
| Parameter | In | Required | Type |
|---|
id | path | yes | string |
Request body
CredentialRevoke (required)
{
"reason": "string"
}
Responses
Example response 200
{
"credential": {
"@context": [
"string"
],
"credentialSubject": {},
"expirationDate": "string",
"id": "string",
"issuanceDate": "string",
"issuer": "string",
"proof": {
"created": "string",
"cryptosuite": "string",
"proofPurpose": "string",
"proofValue": "string",
"type": "string",
"verificationMethod": "string"
},
"type": [
"string"
]
},
"expires_at": 0,
"id": "string",
"issued_at": 0,
"issuer_did": "string",
"issuer_key_id": "string",
"issuer_label": "string",
"kind": "execution",
"node_label": "string",
"parent_id": "string",
"principal": "string",
"revocation_reason": "string",
"revoked_at": 0,
"revoked_by": "string",
"root_id": "string",
"subject_id": "string",
"traverser_id": "string",
"type": "string"
}