/\ ATFGraph /docs
README Downloads
HTTP API & schemas / ATFGraph
Framework reference

This article is retained from the existing framework docs. Self-hosting commands and server-admin access differ from the managed CLI workflow. Start with Get started for the installed product.

Credentials API

Enroll node identities, issue and verify credentials, revoke them and manage node tags. Signing keys remain on the server.

Operations

OperationMethodPath
listCredentialsGET/api/v2/credentials
issueCredentialPOST/api/v2/credentials
listDidsGET/api/v2/credentials/dids
enrolDidPOST/api/v2/credentials/dids
resolveDidPOST/api/v2/credentials/dids/resolve
getDidGET/api/v2/credentials/dids/{label}
listTagLedgerGET/api/v2/credentials/tags
proposeTagsPOST/api/v2/credentials/tags
decideTagsPOST/api/v2/credentials/tags/decide
getTagPolicyGET/api/v2/credentials/tags/policy
putTagPolicyPUT/api/v2/credentials/tags/policy
verifyCredentialPOST/api/v2/credentials/verify
getCredentialGET/api/v2/credentials/{id}
revokeCredentialPOST/api/v2/credentials/{id}/revoke

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

ParameterInRequiredType
issuer_labelquerynostring
kindquerynoCredentialKind
limitquerynointeger
node_labelquerynostring
parent_idquerynostring
revokedquerynoboolean
root_idquerynostring
subject_idquerynostring
traverser_idquerynostring

Responses

StatusBodyMeaning
200CredentialListSuccessful operation
400ErrorResponseStructured API error
401ErrorResponseMissing or invalid credentials
403ErrorResponseRole or ownership denied
404ErrorResponseResource unavailable to this identity
409ErrorResponseRevision, idempotency, immutable version or lease conflict
413ErrorResponseStructured API error
422ErrorResponseCapability input/output schema violation
429ErrorResponseCapacity exceeded
500ErrorResponseStructured API error
503ErrorResponseStructured API error

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

StatusBodyMeaning
201CredentialSuccessful operation
400ErrorResponseStructured API error
401ErrorResponseMissing or invalid credentials
403ErrorResponseRole or ownership denied
404ErrorResponseResource unavailable to this identity
409ErrorResponseRevision, idempotency, immutable version or lease conflict
413ErrorResponseStructured API error
422ErrorResponseCapability input/output schema violation
429ErrorResponseCapacity exceeded
500ErrorResponseStructured API error
503ErrorResponseStructured API error

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

StatusBodyMeaning
200DidEnrolmentListSuccessful operation
400ErrorResponseStructured API error
401ErrorResponseMissing or invalid credentials
403ErrorResponseRole or ownership denied
404ErrorResponseResource unavailable to this identity
409ErrorResponseRevision, idempotency, immutable version or lease conflict
413ErrorResponseStructured API error
422ErrorResponseCapability input/output schema violation
429ErrorResponseCapacity exceeded
500ErrorResponseStructured API error
503ErrorResponseStructured API error

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

StatusBodyMeaning
201DidEnrolmentSuccessful operation
400ErrorResponseStructured API error
401ErrorResponseMissing or invalid credentials
403ErrorResponseRole or ownership denied
404ErrorResponseResource unavailable to this identity
409ErrorResponseRevision, idempotency, immutable version or lease conflict
413ErrorResponseStructured API error
422ErrorResponseCapability input/output schema violation
429ErrorResponseCapacity exceeded
500ErrorResponseStructured API error
503ErrorResponseStructured API error

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

StatusBodyMeaning
200DidResolutionSuccessful operation
400ErrorResponseStructured API error
401ErrorResponseMissing or invalid credentials
403ErrorResponseRole or ownership denied
404ErrorResponseResource unavailable to this identity
409ErrorResponseRevision, idempotency, immutable version or lease conflict
413ErrorResponseStructured API error
422ErrorResponseCapability input/output schema violation
429ErrorResponseCapacity exceeded
500ErrorResponseStructured API error
503ErrorResponseStructured API error

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

ParameterInRequiredType
labelpathyesstring
web_base_urlquerynostring

Responses

StatusBodyMeaning
200DidEnrolmentSuccessful operation
400ErrorResponseStructured API error
401ErrorResponseMissing or invalid credentials
403ErrorResponseRole or ownership denied
404ErrorResponseResource unavailable to this identity
409ErrorResponseRevision, idempotency, immutable version or lease conflict
413ErrorResponseStructured API error
422ErrorResponseCapability input/output schema violation
429ErrorResponseCapacity exceeded
500ErrorResponseStructured API error
503ErrorResponseStructured API error

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

ParameterInRequiredType
labelquerynostring
statequerynoTagState

Responses

StatusBodyMeaning
200TagLedgerSuccessful operation
400ErrorResponseStructured API error
401ErrorResponseMissing or invalid credentials
403ErrorResponseRole or ownership denied
404ErrorResponseResource unavailable to this identity
409ErrorResponseRevision, idempotency, immutable version or lease conflict
413ErrorResponseStructured API error
422ErrorResponseCapability input/output schema violation
429ErrorResponseCapacity exceeded
500ErrorResponseStructured API error
503ErrorResponseStructured API error

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

StatusBodyMeaning
200TagProposalResultSuccessful operation
400ErrorResponseStructured API error
401ErrorResponseMissing or invalid credentials
403ErrorResponseRole or ownership denied
404ErrorResponseResource unavailable to this identity
409ErrorResponseRevision, idempotency, immutable version or lease conflict
413ErrorResponseStructured API error
422ErrorResponseCapability input/output schema violation
429ErrorResponseCapacity exceeded
500ErrorResponseStructured API error
503ErrorResponseStructured API error

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

StatusBodyMeaning
200TagDecisionResultSuccessful operation
400ErrorResponseStructured API error
401ErrorResponseMissing or invalid credentials
403ErrorResponseRole or ownership denied
404ErrorResponseResource unavailable to this identity
409ErrorResponseRevision, idempotency, immutable version or lease conflict
413ErrorResponseStructured API error
422ErrorResponseCapability input/output schema violation
429ErrorResponseCapacity exceeded
500ErrorResponseStructured API error
503ErrorResponseStructured API error

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

StatusBodyMeaning
200TagPolicySuccessful operation
400ErrorResponseStructured API error
401ErrorResponseMissing or invalid credentials
403ErrorResponseRole or ownership denied
404ErrorResponseResource unavailable to this identity
409ErrorResponseRevision, idempotency, immutable version or lease conflict
413ErrorResponseStructured API error
422ErrorResponseCapability input/output schema violation
429ErrorResponseCapacity exceeded
500ErrorResponseStructured API error
503ErrorResponseStructured API error

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

StatusBodyMeaning
200TagPolicySuccessful operation
400ErrorResponseStructured API error
401ErrorResponseMissing or invalid credentials
403ErrorResponseRole or ownership denied
404ErrorResponseResource unavailable to this identity
409ErrorResponseRevision, idempotency, immutable version or lease conflict
413ErrorResponseStructured API error
422ErrorResponseCapability input/output schema violation
429ErrorResponseCapacity exceeded
500ErrorResponseStructured API error
503ErrorResponseStructured API error

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

StatusBodyMeaning
200CredentialVerificationSuccessful operation
400ErrorResponseStructured API error
401ErrorResponseMissing or invalid credentials
403ErrorResponseRole or ownership denied
404ErrorResponseResource unavailable to this identity
409ErrorResponseRevision, idempotency, immutable version or lease conflict
413ErrorResponseStructured API error
422ErrorResponseCapability input/output schema violation
429ErrorResponseCapacity exceeded
500ErrorResponseStructured API error
503ErrorResponseStructured API error

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

ParameterInRequiredType
idpathyesstring
lease_tokenquerynostring
step_idquerynostring
task_idquerynostring

Responses

StatusBodyMeaning
200CredentialSuccessful operation
400ErrorResponseStructured API error
401ErrorResponseMissing or invalid credentials
403ErrorResponseRole or ownership denied
404ErrorResponseResource unavailable to this identity
409ErrorResponseRevision, idempotency, immutable version or lease conflict
413ErrorResponseStructured API error
422ErrorResponseCapability input/output schema violation
429ErrorResponseCapacity exceeded
500ErrorResponseStructured API error
503ErrorResponseStructured API error

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

ParameterInRequiredType
idpathyesstring

Request body

CredentialRevoke (required)

{
  "reason": "string"
}

Responses

StatusBodyMeaning
200CredentialSuccessful operation
400ErrorResponseStructured API error
401ErrorResponseMissing or invalid credentials
403ErrorResponseRole or ownership denied
404ErrorResponseResource unavailable to this identity
409ErrorResponseRevision, idempotency, immutable version or lease conflict
413ErrorResponseStructured API error
422ErrorResponseCapability input/output schema violation
429ErrorResponseCapacity exceeded
500ErrorResponseStructured API error
503ErrorResponseStructured API error

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"
}
ATFGraph documentationHosted workflow · Framework reference