Skip to main content

API Integration for Authentic Sources

This guide covers integrating with the SIROS ID Issuer using REST and gRPC APIs—ideal for organizations where credential data comes from authoritative systems rather than identity providers.

When to Use API Integration

Choose API integration when:

  • Authentic source systems (HR databases, student information systems, government registries) need to push data directly
  • Batch issuance is required for large-scale credential provisioning
  • Pre-authorized flows enable users to collect credentials without additional authentication
  • Custom identity matching logic is needed beyond standard IAM attributes
  • Non-IAM workflows where the user doesn't authenticate via SAML/OIDC
Comparison
Integration TypeBest ForUser Auth
SAML IdPFederation, existing SSOSAML assertion
OIDC ProviderModern IdP, claims-basedID token
API IntegrationBackend systems, batch, automationPre-authorized or PID-based

Architecture Overview

API integration uses the Datastore API for document management and the Issuer gRPC API for credential signing:

Datastore REST API

The Datastore API allows authentic sources to upload documents, manage identities, and trigger credential issuance flows.

Base URL

https://issuer.example.org/api/v1

Authentication

API requests require authentication via:

  • API Key: X-API-Key: <your-api-key> header
  • mTLS: Client certificate authentication (recommended for production)

Endpoint Summary

MethodEndpointDescription
POST/uploadUpload document data for future credential issuance
POST/notificationGet QR code and deep link for credential pickup
PUT/document/identityAdd identity mapping to a document
DELETE/document/identityRemove identity mapping from a document
DELETE/documentDelete a document
POST/document/collect_idRetrieve document with identity matching
POST/identity/mappingMap identity attributes to internal person ID
POST/document/listList available documents for a person
POST/documentRetrieve a specific document by ID
POST/document/revokeRevoke a credential

Document Upload Flow

Step 1: Upload Document Data

Upload the credential data before the user requests it:

POST /api/v1/upload
Content-Type: application/json
X-API-Key: your-api-key

{
"meta": {
"authentic_source": "hr.example.org",
"vct": "urn:eudi:diploma:1",
"document_id": "diploma-2025-001234",
"real_data": true,
"credential_valid_from": 1735689600,
"credential_valid_to": 1767225600
},
"identities": [
{
"authentic_source_person_id": "EMP-12345",
"family_name": "Smith",
"given_name": "Alice",
"birth_date": "1990-05-15"
}
],
"document_display": {
"description_short": "Bachelor of Science in Computer Science",
"description_long": "Awarded by Example University, May 2025",
"valid_from": 1735689600,
"valid_to": 1767225600
},
"document_data": {
"degree_type": "Bachelor of Science",
"field_of_study": "Computer Science",
"issuing_institution": "Example University",
"graduation_date": "2025-05-15",
"gpa": "3.8",
"credits_earned": 120
},
"document_data_version": "1.0.0"
}

Response: 200 OK on success

Step 2: Generate Credential Offer

Get a QR code and deep link to send to the user:

POST /api/v1/notification
Content-Type: application/json
X-API-Key: your-api-key

{
"authentic_source": "hr.example.org",
"vct": "urn:eudi:diploma:1",
"document_id": "diploma-2025-001234"
}

Response:

{
"qr": {
"base64_image": "data:image/png;base64,iVBORw0KGgo...",
"deep_link": "openid-credential-offer://?credential_offer_uri=https://issuer.example.org/offers/abc123"
}
}

Step 3: Notify the User

Send the QR code or deep link to the user via:

  • Email notification
  • Portal display
  • SMS with deep link
  • In-app notification

The user scans the QR or clicks the link to initiate credential collection in their wallet.


Identity Management

Adding Identity to a Document

If multiple people can collect a credential (e.g., legal representatives), add identities:

PUT /api/v1/document/identity
Content-Type: application/json

{
"authentic_source": "hr.example.org",
"vct": "urn:eudi:diploma:1",
"document_id": "diploma-2025-001234",
"identity": {
"authentic_source_person_id": "REP-67890",
"family_name": "Jones",
"given_name": "Bob",
"birth_date": "1985-03-22"
}
}

Identity Matching

When a user presents their PID (Person Identification Data) credential to collect a document, the issuer performs identity matching:

POST /api/v1/identity/mapping
Content-Type: application/json

{
"authentic_source": "hr.example.org",
"identity": {
"schema": {
"name": "SE",
"version": "1.0.0"
},
"family_name": "Smith",
"given_name": "Alice",
"birth_date": "1990-05-15"
}
}

Response:

{
"data": {
"authentic_source_person_id": "EMP-12345"
}
}

The schema field identifies the identity schema used (e.g. "SE" for Sweden). The version must match the version used when the document was uploaded.

The matching algorithm compares:

  • schema (required)
  • family_name (required)
  • given_name (required)
  • birth_date (required)

Pre-Authorized Code Flow

For server-to-server issuance where the user has already been authenticated by your system:

Configuration

Enable pre-authorized code flow in the issuer configuration:

issuer:
pre_authorized_code:
enabled: true
# Optional: require user to enter a PIN
pin_required: false
# Code expiration (default: 5 minutes)
code_ttl: 300

Credential Offer Format

The deep link contains a credential offer with pre-authorized code grant:

{
"credential_issuer": "https://issuer.example.org",
"credential_configuration_ids": ["urn:eudi:diploma:1"],
"grants": {
"urn:ietf:params:oauth:grant-type:pre-authorized_code": {
"pre-authorized_code": "oaKazRN8I0IbtZ...",
"tx_code": {
"input_mode": "numeric",
"length": 6,
"description": "Enter the PIN sent to your email"
}
}
}
}

Revocation

Revoking a Credential

When a credential needs to be revoked (e.g., employee termination, certificate withdrawal):

POST /api/v1/document/revoke
Content-Type: application/json

{
"authentic_source": "hr.example.org",
"vct": "urn:eudi:diploma:1",
"revocation": {
"id": "diploma-2025-001234",
"reason": "Certificate withdrawn due to academic misconduct",
"revoke_at": 1735689600
}
}

The issuer updates the Token Status List, and verifiers will see the credential as revoked.

Revocation with Replacement

If issuing a replacement credential:

{
"revocation": {
"id": "diploma-2025-001234",
"reference": {
"authentic_source": "hr.example.org",
"vct": "urn:eudi:diploma:1",
"document_id": "diploma-2025-001234-v2"
}
}
}

gRPC Integration

For advanced integrations, the Issuer Service exposes a gRPC API for direct credential signing.

Service Definition

service IssuerService {
rpc MakeSDJWT (MakeSDJWTRequest) returns (MakeSDJWTReply) {}
rpc MakeMDoc (MakeMDocRequest) returns (MakeMDocReply) {}
rpc MakeVC20 (MakeVC20Request) returns (MakeVC20Reply) {}
rpc JWKS (Empty) returns (JwksReply) {}
}

SD-JWT Credential

message MakeSDJWTRequest {
string scope = 1; // Credential scope (e.g., "diploma")
bytes documentData = 2; // JSON document data
jwk jwk = 3; // Holder's public key for binding
string integrity = 5; // Integrity token
bytes vctm = 6; // VCTM JSON bytes
}

mDL/mDoc Credential

message MakeMDocRequest {
string scope = 1; // Credential scope
string doc_type = 2; // e.g., "org.iso.18013.5.1.mDL"
bytes document_data = 3; // JSON encoded mDL data
bytes device_public_key = 4; // CBOR encoded COSE_Key
string device_key_format = 5; // "cose", "jwk", or "x509"
}

Connection

import (
"google.golang.org/grpc"
pb "vc/internal/gen/issuer/apiv1_issuer"
)

conn, err := grpc.Dial("issuer.example.org:9090", grpc.WithTransportCredentials(creds))
client := pb.NewIssuerServiceClient(conn)

reply, err := client.MakeSDJWT(ctx, &pb.MakeSDJWTRequest{
Scope: "diploma",
DocumentData: documentJSON,
Jwk: holderKey,
Vctm: vctmBytes,
})

Batch Issuance

For large-scale credential provisioning:

1. Bulk Upload

# Upload multiple documents
for doc in documents/*.json; do
curl -X POST https://issuer.example.org/api/v1/upload \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d @"$doc"
done

2. Generate Offers in Batch

POST /api/v1/notification/batch
Content-Type: application/json

{
"authentic_source": "hr.example.org",
"vct": "urn:eudi:diploma:1",
"document_ids": [
"diploma-2025-001234",
"diploma-2025-001235",
"diploma-2025-001236"
]
}

3. Bulk Notification

Integrate with your notification system to send credential offers to all recipients.


Configuration

Authentic Source Configuration

Register your authentic source in the issuer configuration:

authentic_sources:
hr.example.org:
identifier: "hr.example.org"
country_code: "SE"

# API key for authentication
api_key_hash: "$2a$12$..."

# Supported credential types
credential_types:
diploma:
vct: "urn:eudi:diploma:1"
vctm_path: "/metadata/vctm_diploma.json"
format: "dc+sd-jwt"

employee_badge:
vct: "urn:example:employee:1"
vctm_path: "/metadata/vctm_employee.json"
format: "dc+sd-jwt"

# Optional: webhook for status updates
notification_endpoint:
url: "https://hr.example.org/webhooks/credential-status"
auth_header: "X-Webhook-Secret"

Identity Matching Rules

Configure how identity attributes are matched:

identity_matching:
# Required attributes for matching
required_attributes:
- family_name
- given_name
- birth_date

# Fuzzy matching tolerance
fuzzy_matching:
enabled: true
threshold: 0.85

# Date format normalization
date_formats:
- "2006-01-02" # ISO 8601
- "02/01/2006" # European
- "01/02/2006" # US

Error Handling

Error Response Format

{
"error": {
"code": "DOCUMENT_NOT_FOUND",
"message": "No document found with the specified ID",
"details": {
"authentic_source": "hr.example.org",
"document_id": "invalid-id"
}
}
}

Common Error Codes

CodeHTTP StatusDescription
DOCUMENT_NOT_FOUND404Document does not exist
IDENTITY_MISMATCH403Identity attributes do not match
ALREADY_REVOKED409Credential already revoked
INVALID_FORMAT400Request body is malformed
UNAUTHORIZED401Invalid or missing API key
RATE_LIMITED429Too many requests

Security Considerations

  1. API Key Rotation: Rotate API keys regularly and use environment variables
  2. mTLS: Use mutual TLS for production deployments
  3. Input Validation: The issuer validates all document data against VCTM schemas
  4. Audit Logging: All API operations are logged for compliance
  5. Rate Limiting: Implement rate limiting to prevent abuse

Next Steps