# CredentialProvider SDK reference

> TypeScript contract reference for provider metadata, schemas, operations, lifecycle results, setup hints, and context capabilities.

Import from `@constal/sdk`. Definitions are validated at module load and probed again by the managed builder.

## Primary exports {#primary-exports}

```ts
import {
  credentialProvider,
  credentialProviderConfigSchema,
  credentialProviderSetupMetadata,
  type CredentialProviderDefinition,
  type CredentialProviderPackage,
  type CredentialProviderPackageMetadata,
  type CredentialProviderContext,
  type CredentialMintRequest,
  type CredentialMintResult,
  type CredentialInteractionStartRequest,
  type CredentialInteractionAdvanceRequest,
  type CredentialInteractionAction,
  type CredentialInteractionEvent,
  type CredentialInteractionResult,
  type CredentialMaterialRequest,
} from "@constal/sdk";
```

## Definition fields {#definition-fields}

```ts
const definition: CredentialProviderDefinition = {
  id: "example-token", version: "1.0.0",
  displayName: "Example token", description: "Mints a short-lived token.",
  credentialSlots: ["bootstrap-token"],
  configSchema: credentialProviderConfigSchema({ type: "object", additionalProperties: false }),
  credentialConfigSchema: credentialProviderConfigSchema({ type: "object", additionalProperties: false }),
  rotation: { mode: "manual", intervalMs: null, overlapMs: 0, maxAgeMs: null, refreshBeforeMs: 0 },
  egress: { rules: [] },
  mintRecovery: { kind: "outcome-unknown" },
  async mint(_request, context) {
    const bootstrap = await context.secret("bootstrap-token");
    return { material: bootstrap.value };
  },
};

export default credentialProvider(definition);
```

The core identity, descriptions, schemas, bootstrap slots, rotation, egress, and `mint` are required. Documentation, Console setup hints, generic interaction, verification, and source-side destruction are optional.

## Interaction {#interaction}

```ts
interaction: {
  origins: ["https://example.com"],
  async start(request: CredentialInteractionStartRequest): Promise<CredentialInteractionResult> {
    return { action: { kind: "redirect",
      url: `https://example.com/connect?state=${encodeURIComponent(request.state)}` } };
  },
  async advance(request: CredentialInteractionAdvanceRequest): Promise<CredentialInteractionResult> {
    if (request.event.kind !== "callback") throw new Error("Expected callback");
    return { action: { kind: "complete", material: await exchange(request.event.parameters.code) } };
  }
}
```

The action vocabulary is finite: `redirect`, `form`, `display`, `wait`, and `complete`. Each action admits exactly one next event class. See [Provider interaction lifecycle](/docs/credentials/providers/interaction.md) for the complete state machine and security rules.

## Provider context {#provider-context}

```ts
async function mint(request: CredentialMintRequest, context: CredentialProviderContext): Promise<CredentialMintResult> {
  const bootstrap = await context.secret("bootstrap-token");
  const prior = await context.state.get("refresh-state");
  const response = await context.egress({
    url: "https://api.example.com/oauth/token", method: "POST",
    headers: { authorization: `Bearer ${bootstrap.value}` },
    bodyBase64: btoa(JSON.stringify({ prior })), maximumResponseBytes: 65_536, maximumRedirects: 0,
  });
  await context.audit({ operation: "mint", status: response.status });
  return { material: atob(response.bodyBase64), privateState: request.privateState };
}
```

`secret`, bounded `egress`, private `state`, immutable `store`, and non-secret `audit` are provider capabilities. They do not exist on Agent `Ctx` or `ChannelContext`; provider code receives only the bounded lifecycle capabilities declared by its contract.

## Result rules {#result-rules}

```ts
const minted: CredentialMintResult = {
  material: accessToken,
  expiresAt: Date.now() + 3_600_000,
  privateState: refreshToken,
};
const verified = { verified: true };
const destroyed = { destroyed: true };
```

Consumer `material` and provider-private lifecycle state are separate. Never place refresh state in consumer material or access material in private state.

## Resource selectors {#resource-selectors}

```ts
import { scopedBindingKey, type ScopedCredentialRef } from "@constal/sdk";

const credential: ScopedCredentialRef = {
  kind: "scoped", key: scopedBindingKey("github"), owner: "customer", required: true,
};
```

A scoped Resource selector additionally pins its Resource contract. Read [Scoped bindings](/docs/credentials/scoped-bindings.md) for admission-time resolution.

## Machine-readable schemas {#machine-readable-schemas}

- [Credential creation schema](/docs/credentials/reference/credential-create.schema.json)
- [Provider installation schema](/docs/credentials/reference/provider-install.schema.json)
- [Provider setup metadata schema](/docs/credentials/reference/provider-setup.schema.json)
