> ## Documentation Index
> Fetch the complete documentation index at: https://docs.beltic.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Batch Issuing Credentials

> Issue many credentials in a single async job — ideal for backfills, bulk onboarding, and CLI uploads.

## Overview

The batch-issue endpoint accepts up to 10,000 credentials in a single call and processes them asynchronously. You get a `job_id` back immediately; the credentials are issued in the background by a worker Lambda, and you poll job status or subscribe to a webhook stream to find out when the batch is done.

Use it for:

* One-time backfills when you've already KYB-verified a set of businesses out-of-band.
* CLI-driven uploads where an operator pastes a JSON file with thousands of records.
* Periodic syncs from an internal system that issues credentials nightly.

For low-volume, interactive issuance (≤ 10 credentials), call `POST /v1/credentials` directly per credential — it's faster and synchronous.

## Prerequisites

* A Beltic API key with `credentials:write` permission
* A JSON array of credential payloads (each one a valid `POST /v1/credentials` body)

## Step 1: Submit the Batch

```bash theme={null}
curl -X POST https://api.beltic.com/v1/credentials/batch-issue \
  -H "X-Api-Key: $BELTIC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "credentials": [
      {
        "credential_type": "business",
        "subject": { "id": "biz_001", "type": "organisation", "name": "Acme Corp" },
        "claims": { "kyb_status": "approved", "verified_at": "2026-05-20T00:00:00Z", "jurisdiction": "US-DE" }
      },
      {
        "credential_type": "business",
        "subject": { "id": "biz_002", "type": "organisation", "name": "Widget Co" },
        "claims": { "kyb_status": "approved", "verified_at": "2026-05-20T00:00:00Z", "jurisdiction": "US-NY" }
      }
    ]
  }'
```

### Response

```json theme={null}
{
  "job_id": "job_01HQ7Q...",
  "status": "queued",
  "total": 2,
  "processed": 0,
  "succeeded": 0,
  "failed": 0,
  "created_at": "2026-05-21T16:00:00Z"
}
```

The batch is accepted and queued. The HTTP response returns within \~200ms; actual issuance happens in the background.

## Step 2: Poll for Status (or use webhooks)

Poll the same job\_id endpoint to check progress:

```bash theme={null}
curl "https://api.beltic.com/v1/credentials/batch-issue/$JOB_ID" \
  -H "X-Api-Key: $BELTIC_API_KEY"
```

```json theme={null}
{
  "job_id": "job_01HQ7Q...",
  "status": "completed",
  "total": 2,
  "processed": 2,
  "succeeded": 2,
  "failed": 0,
  "credential_ids": [
    "cred_01HQ7R...",
    "cred_01HQ7S..."
  ],
  "started_at": "2026-05-21T16:00:01Z",
  "completed_at": "2026-05-21T16:00:08Z"
}
```

Status progression: `queued` → `processing` → `completed` (or `failed` if every item errored).

### Webhook Alternative

For long-running batches you don't want to poll, create a webhook stream that fires on `credential.batch_completed`:

```bash theme={null}
curl -X POST https://api.beltic.com/v1/audit/streams \
  -H "X-Api-Key: $BELTIC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.example.com/webhooks/beltic",
    "actions": ["credential.batch_completed", "credential.batch_failed"]
  }'
```

See the audit-streams endpoint reference for signature verification details.

## Partial Failures

A batch is treated as best-effort: if one credential fails validation (e.g. an invalid `kyb_status`), the rest still issue. The job's `failed` count reflects how many didn't make it; per-item failure details are surfaced in the job response's `errors` array:

```json theme={null}
{
  "job_id": "job_01HQ7Q...",
  "status": "completed",
  "total": 100,
  "processed": 100,
  "succeeded": 97,
  "failed": 3,
  "credential_ids": ["cred_...", "cred_..."],
  "errors": [
    {
      "index": 42,
      "code": "validation_failed",
      "message": "claims.kyb_status: expected 'approved' | 'pending' | 'declined' | 'manual_review', got 'verified'"
    }
  ]
}
```

The `index` field is the 0-based position of the failed item in your original `credentials` array — use it to reconcile with your source data.

## Limits

| Constraint                    | Value                            |
| ----------------------------- | -------------------------------- |
| Max items per batch           | 10,000                           |
| Max request body size         | 25 MB                            |
| Concurrent batch jobs per org | 10                               |
| Per-org batch throughput      | 100 credentials/second sustained |

Submitting a 100k-credential backfill? Split it across multiple jobs.

## Idempotency

Like single-issue, batch-issue supports the `Idempotency-Key` header. Use one key per logical batch — re-submitting with the same key within 24 hours returns the original `job_id` without enqueuing duplicate work.

## CLI Usage

The Beltic CLI wraps batch-issue with a progress bar and per-item retry. If you have a JSON file of credential payloads:

```bash theme={null}
beltic credentials batch-issue --file ./credentials.json --wait
```

The CLI calls `POST /v1/credentials/batch-issue`, polls for completion, and exits non-zero if any item failed. Pair it with CI/CD to run nightly backfills.

## Next Steps

<CardGroup cols={2}>
  <Card title="Verify Credentials" icon="shield-check" href="/guides/credentials/verifying-a-credential">
    Validate any of the issued credentials.
  </Card>

  <Card title="Audit Events" icon="clipboard-list" href="/api-reference/endpoint/audit-events-list">
    Query the audit log for batch issuance events.
  </Card>
</CardGroup>
