Merchant Onboarding Service
1. Overview
The Merchant Onboarding Service is a dedicated microservice inside the CDE project (peakpos-cde). Its sole purpose is to bridge the gap between the gateway's TransIT credentials and physical payment devices that need those credentials. It handles TransIT MerchantActivation API calls and pushes resulting credentials to NexGO's XTMS device management system.
Why this service exists: TransIT credentials (deviceID, transactionKey) must never leave the CDE boundary. External systems (e.g., PeakPOS Management API) can only trigger provisioning workflows — they never see, receive, or transmit raw credentials.
Credential model: Each location is assigned a credential profile (the TransIT "var sheet"). Activation provisions one GATEWAY profile per location — there is no per-channel (web/mobile/POS) credential split. The origination channel of a payment is recorded on transactions.source (GATEWAY / ONLINE / SEMI_INTEGRATED), not by selecting a different credential profile.
2. Responsibilities
| Responsibility | Description |
|---|---|
| Merchant activation | Call TransIT MerchantActivation API to generate transactionKey + activate deviceID |
| Device credential push | Push TransIT credentials to NexGO XTMS by device serial number |
| Credential storage | Encrypt and store TransIT credentials in CDE Spanner via Cloud KMS |
| Credential rotation | Rotate transactionKeys on demand or on schedule |
| Provisioning audit trail | Immutable log of every provisioning action (who, what, when, outcome) |
| Job orchestration | Manage async provisioning jobs with retry, dead-letter, and manual replay |
| Status reporting | Return provisioning job status to callers (without exposing credentials) |
3. Architecture Context
┌──────────────────────────────────────────────┐
│ GCP Project: peakpos (OUT of CDE) │
│ │
│ Management API │
│ │ │
│ │ POST /api/v1/provisioning/jobs │
│ │ OAuth token (scope: provision:request) │
│ │ Body: { locationId, deviceSerial } │
│ │ Response: { jobId, status } │
└────┼─────────────────────────────────────────┘
│
│ Cloud Run IAM-gated HTTPS
│
┌────┼──────────────────────────────────────────────────────────────┐
│ ▼ │
│ Merchant Onboarding Service (CDE project) │
│ │ │
│ ├──→ TransIT MerchantActivation API (get credentials) │
│ ├──→ CDE Spanner (store encrypted credentials) │
│ ├──→ Cloud KMS (encrypt/decrypt credential material) │
│ └──→ NexGO XTMS API (push credentials to device by serial) │
│ │
│ GCP Project: peakpos-cde (PCI SCOPED) │
└───────────────────────────────────────────────────────────────────┘
4. API Specification
Authentication
All endpoints require a Gateway OAuth token issued by the Gateway Auth Service:
Authorization: Bearer <gateway-oauth-token>
Tokens are scoped — callers can only access endpoints matching their granted scopes.
Operationally, provisioning authorization is anchored to the location being activated and the organization that owns it.
4.1 External API (called by clients like PeakPOS Management API)
Create Provisioning Job
POST /api/v1/provisioning/jobs
Required Scope: provision:request
Request:
{
"locationId": "loc_abc123",
"deviceSerial": "N5-2024-001234",
"action": "ACTIVATE", // ACTIVATE | DEACTIVATE | ROTATE_KEY
"callbackUrl": "https://api.peakgateway.co/management/webhooks/provisioning", // optional
"requestedBy": "user_xyz789", // identity of the human who initiated this
"metadata": {
"storeId": "store_456",
"terminalId": "term_789",
"notes": "New c-store install at 123 Main St"
}
}
Response (202 Accepted):
{
"jobId": "prov_job_abc123",
"status": "QUEUED",
"locationId": "loc_abc123",
"deviceSerial": "N5-2024-001234",
"action": "ACTIVATE",
"createdAt": "2026-03-08T15:00:00Z",
"estimatedCompletionSeconds": 30
}
Note: 202 (not 200) — provisioning is async. The response contains a job ID for polling or the caller can register a callback URL.
Get Job Status
GET /api/v1/provisioning/jobs/{jobId}
Required Scope: provision:request
Response (200):
{
"jobId": "prov_job_abc123",
"status": "COMPLETED", // QUEUED | IN_PROGRESS | COMPLETED | FAILED | RETRYING
"locationId": "loc_abc123",
"deviceSerial": "N5-2024-001234",
"action": "ACTIVATE",
"steps": [
{
"step": "TRANSIT_ACTIVATION",
"status": "COMPLETED",
"completedAt": "2026-03-08T15:00:05Z"
},
{
"step": "CREDENTIAL_STORAGE",
"status": "COMPLETED",
"completedAt": "2026-03-08T15:00:06Z"
},
{
"step": "XTMS_PUSH",
"status": "COMPLETED",
"completedAt": "2026-03-08T15:00:12Z"
}
],
"createdAt": "2026-03-08T15:00:00Z",
"completedAt": "2026-03-08T15:00:12Z",
"error": null
}
Note: Steps are visible for transparency. Credential values are NEVER included in any response.
List Jobs
GET /api/v1/provisioning/jobs?locationId={locationId}&status={status}&page={page}&size={size}
Required Scope: provision:request
Response (200):
{
"jobs": [ ... ],
"page": 1,
"size": 20,
"totalElements": 3
}
Cancel Job
POST /api/v1/provisioning/jobs/{jobId}/cancel
Required Scope: provision:request
Response (200):
{
"jobId": "prov_job_abc123",
"status": "CANCELED",
"canceledAt": "2026-03-08T15:00:03Z",
"canceledBy": "user_xyz789"
}
Only cancelable if status is
QUEUED. In-progress jobs cannot be canceled.
Retry Failed Job
POST /api/v1/provisioning/jobs/{jobId}/retry
Required Scope: provision:request
Response (202 Accepted):
{
"jobId": "prov_job_abc123",
"status": "QUEUED",
"retryCount": 2,
"retriedAt": "2026-03-08T16:00:00Z"
}
4.2 Internal API (called by other CDE services only)
Internal route families are exposed under /internal/locations. Callers pass
the location id they are authorized to operate on.
Get Credential Metadata
The credential metadata endpoint is VPC-internal only, never exposed through the
API Gateway, service-account authenticated, and fully audit-logged. It reads the
single active credential_profiles row for the location and returns only
API-safe metadata. The live TSYS transaction key is never returned by this
endpoint; callers rotate keys server-side with the rotation endpoint below.
GET /internal/locations/{locationId}/credentials
Required: Service-to-service IAM (not OAuth; internal VPC only)
Response (200):
{
"locationId": "loc_abc123",
"deviceId": "88700000123456",
"activatedAt": "2026-03-08T15:00:05Z",
"lastRotatedAt": null
}
Rotate Credentials
POST /internal/locations/{locationId}/rotate
Required: Service-to-service IAM
Caller: Processing Service or scheduled job
Response (200):
{
"locationId": "loc_abc123",
"rotatedAt": "2026-03-08T15:00:00Z",
"previousKeyDeactivated": true,
"xtmsPushStatus": "COMPLETED"
}
TransIT Activation Metadata and Rotation
Activation endpoints return metadata only and never return the plaintext activation password. Use the rotation endpoint to rotate the TSYS transaction key server-side.
GET /internal/locations/{locationId}/transit-activation
POST /internal/locations/{locationId}/transit-activation/rotate
POST /internal/locations/{locationId}/transit-activation
POST /internal/locations/{locationId}/transit-activation/reuse
GET /internal/locations/{locationId}/transit-state
5. Provisioning Job State Machine
┌─────────┐
┌──────────>│ QUEUED │
│ └────┬────┘
│ │
(retry) │ worker picks up
│ ▼
│ ┌──────────────┐
├───────────│ IN_PROGRESS │
│ └──┬───────┬───┘
│ │ │
│ success failure
│ │ │
│ ▼ ▼
│ ┌───────────┐ ┌────────────┐
│ │ COMPLETED │ │ RETRYING │──── max retries exceeded ──→ FAILED
│ └───────────┘ └─────┬──────┘
│ │
└─────────────────────────┘
CANCELED ← (only from QUEUED, via cancel endpoint)
Job Steps (executed sequentially)
| Step | Action | Rollback on failure |
|---|---|---|
TRANSIT_ACTIVATION | Call TransIT MerchantActivation API | None (idempotent — can retry safely) |
CREDENTIAL_STORAGE | Encrypt credentials via KMS, store in CDE Spanner | Delete stored record |
XTMS_PUSH | Push credentials to NexGO XTMS by device serial | Mark as pending manual intervention |
Retry Policy
| Failure type | Retry strategy |
|---|---|
| TransIT API timeout/5xx | Exponential backoff: 5s, 15s, 45s (max 3 retries) |
| TransIT API 4xx | No retry (invalid request — fail immediately) |
| XTMS API timeout/5xx | Exponential backoff: 10s, 30s, 90s (max 3 retries) |
| XTMS API 4xx | No retry — fail and alert |
| KMS/Spanner errors | Exponential backoff: 2s, 4s, 8s (max 3 retries) |
| Max retries exceeded | Move to dead-letter queue, alert on-call, status = FAILED |
6. IAM & Service Account Matrix
Service Accounts
| Service Account | GCP Project | Purpose |
|---|---|---|
merchant-onboarding-sa@peakpos-cde | peakpos-cde | Runs the Merchant Onboarding Service |
processing-sa@peakpos-cde | peakpos-cde | Processing Service — calls internal credential endpoint |
gateway-auth-sa@peakpos-cde | peakpos-cde | Gateway Auth Service — validates OAuth tokens |
mgmt-api-sa@peakpos | peakpos | Management API — calls external provisioning API |
IAM Role Bindings
| Principal | Role | Resource | Purpose |
|---|---|---|---|
merchant-onboarding-sa | roles/secretmanager.secretAccessor | TransIT developer credentials secret | Read TransIT developerID/developerKey |
merchant-onboarding-sa | roles/cloudkms.cryptoKeyEncrypterDecrypter | Credential encryption key | Encrypt/decrypt merchant transactionKeys |
merchant-onboarding-sa | roles/spanner.databaseUser | CDE Spanner instance | Read/write provisioning tables |
merchant-onboarding-sa | roles/pubsub.publisher | provisioning-events topic | Publish provisioning audit events |
processing-sa | roles/run.invoker | Merchant Onboarding Service (internal) | Call internal credential endpoint |
mgmt-api-sa@peakpos | roles/run.invoker | Merchant Onboarding Service (external) | Call external provisioning API |
mgmt-api-sa@peakpos | (none on secrets/KMS/Spanner) | — | Cannot access credentials, keys, or CDE data |
OAuth Scope Matrix
| Scope | Who gets it | What it allows |
|---|---|---|
provision:request | PeakPOS Management API, Gateway Portal users | Create/view/cancel/retry provisioning jobs |
provision:admin | Gateway Portal admins only | View audit logs, manual replay, configuration |
merchant:activate | PeakPOS Management API, Gateway Portal users | Trigger merchant activation in TransIT |
credentials:read | Processing Service only (via IAM, not OAuth) | Read raw TransIT credentials |
credentials:rotate | Processing Service, scheduled jobs (via IAM) | Rotate TransIT credentials |
7. Data Model (CDE Spanner)
provisioning_jobs
CREATE TABLE provisioning_jobs (
job_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
location_id VARCHAR(50) NOT NULL,
device_serial VARCHAR(100) NOT NULL,
action VARCHAR(20) NOT NULL, -- ACTIVATE, DEACTIVATE, ROTATE_KEY
status VARCHAR(20) NOT NULL, -- QUEUED, IN_PROGRESS, COMPLETED, FAILED, RETRYING, CANCELED
requested_by VARCHAR(100) NOT NULL, -- OAuth subject (user ID)
client_id VARCHAR(100) NOT NULL, -- OAuth client (e.g., "peakpos-mgmt-api")
callback_url VARCHAR(500),
metadata JSONB DEFAULT '{}',
current_step VARCHAR(30), -- Current step being executed
retry_count INTEGER DEFAULT 0,
error_message TEXT,
error_code VARCHAR(20),
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
started_at TIMESTAMPTZ,
completed_at TIMESTAMPTZ,
canceled_at TIMESTAMPTZ
);
CREATE INDEX idx_prov_jobs_location ON provisioning_jobs (location_id);
CREATE INDEX idx_prov_jobs_status ON provisioning_jobs (status);
CREATE INDEX idx_prov_jobs_client ON provisioning_jobs (client_id);
credential_profiles (encrypted)
Credential profiles are the authoritative encrypted credential surface. A
profile is owned by an organization and assigned to one or more locations. Each
profile represents the TSYS TransIT credential set needed for processing; there
is no per-channel credential split. Origination channel is recorded on
transactions.source (GATEWAY / ONLINE / SEMI_INTEGRATED), not by
selecting a different credential profile.
CREATE TABLE credential_profiles (
credential_profile_id VARCHAR(64) PRIMARY KEY,
organization_id VARCHAR(64) NOT NULL,
processor_type VARCHAR(32) NOT NULL,
processor_platform VARCHAR(32) NOT NULL,
encrypted_payload BYTEA NOT NULL,
status VARCHAR(20) NOT NULL,
created_at TIMESTAMPTZ NOT NULL,
updated_at TIMESTAMPTZ NOT NULL
);
provisioning_audit_log (append-only)
CREATE TABLE provisioning_audit_log (
log_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
job_id UUID NOT NULL,
event_type VARCHAR(50) NOT NULL, -- See audit events below
actor VARCHAR(100) NOT NULL, -- User ID or service account
actor_type VARCHAR(20) NOT NULL, -- USER, SERVICE, SYSTEM
client_id VARCHAR(100), -- OAuth client ID
location_id VARCHAR(50) NOT NULL,
device_serial VARCHAR(100),
details JSONB DEFAULT '{}', -- Step-specific details (NEVER contains credentials)
ip_address VARCHAR(45),
timestamp TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_prov_audit_location ON provisioning_audit_log (location_id);
CREATE INDEX idx_prov_audit_job ON provisioning_audit_log (job_id);
CREATE INDEX idx_prov_audit_time ON provisioning_audit_log (timestamp);
8. Audit Events
Every action produces an immutable audit log entry. Credential values are NEVER logged.
| Event Type | Trigger | Details captured |
|---|---|---|
PROVISION_REQUESTED | Job created via external API | locationId, deviceSerial, action, requestedBy, clientId, IP |
PROVISION_STARTED | Worker picks up job | jobId, step |
TRANSIT_ACTIVATION_SUCCESS | TransIT MerchantActivation returns 200 | locationId, transitMerchantId (not keys), responseCode |
TRANSIT_ACTIVATION_FAILED | TransIT returns error | locationId, errorCode, errorMessage, retryCount |
CREDENTIAL_STORED | Encrypted credential written to Spanner | locationId, keyVersion, kmsKeyName |
CREDENTIAL_ROTATED | Key rotation completed | locationId, previousKeyVersion, newKeyVersion |
CREDENTIAL_ACCESSED | Processing Service reads credentials | locationId, accessedBy (service account), purpose |
XTMS_PUSH_SUCCESS | XTMS accepts credential push | locationId, deviceSerial, xtmsResponseCode |
XTMS_PUSH_FAILED | XTMS rejects or times out | locationId, deviceSerial, errorCode, retryCount |
PROVISION_COMPLETED | All steps finished successfully | jobId, totalDurationMs |
PROVISION_FAILED | Max retries exceeded | jobId, failedStep, errorCode, errorMessage |
PROVISION_CANCELED | Job canceled by user | jobId, canceledBy, IP |
PROVISION_RETRIED | Manual retry triggered | jobId, retriedBy, retryCount |
CREDENTIAL_DEACTIVATED | Location deactivated | locationId, deactivatedBy, reason |
9. Security Controls
Credential Handling
- Encryption at rest: All TransIT credentials encrypted via Cloud KMS (AES-256-GCM) before Spanner write
- Encryption in transit: TLS 1.2+ on all connections (internal and external)
- Ephemeral in memory: Credentials decrypted only for the duration of the XTMS push call, then zeroed
- No logging of secrets: Credential values excluded from all application logs, audit logs, and error messages
- No credential return: External API never returns credential values — only job status
Network Isolation
- Service runs on Cloud Run in the CDE VPC
- External API reachable only through Gateway API Gateway (Cloud Endpoints) with OAuth validation
- Internal API reachable only via VPC-internal Cloud Run URL (no public endpoint)
- Egress restricted to: TransIT API, XTMS API, CDE Spanner, Cloud KMS, Pub/Sub
Rate Limiting
| Endpoint | Limit | Per |
|---|---|---|
POST /api/v1/provisioning/jobs | 10/min | client_id |
GET /api/v1/provisioning/jobs/{jobId} | 60/min | client_id |
GET /internal/locations/{locationId}/credentials | 100/min | service account |
10. Pub/Sub Events
The service publishes events to the provisioning-events topic for async consumers.
{
"eventType": "PROVISION_COMPLETED",
"jobId": "prov_job_abc123",
"locationId": "loc_abc123",
"deviceSerial": "N5-2024-001234",
"action": "ACTIVATE",
"timestamp": "2026-03-08T15:00:12Z",
"steps": [
{ "step": "TRANSIT_ACTIVATION", "status": "COMPLETED", "durationMs": 5000 },
{ "step": "CREDENTIAL_STORAGE", "status": "COMPLETED", "durationMs": 1000 },
{ "step": "XTMS_PUSH", "status": "COMPLETED", "durationMs": 6000 }
]
}
Subscribers
| Subscriber | Event types | Purpose |
|---|---|---|
| Gateway Portal | All | Real-time status updates in UI |
| Callback delivery | PROVISION_COMPLETED, PROVISION_FAILED | POST to caller's callbackUrl |
| Alerting | PROVISION_FAILED, XTMS_PUSH_FAILED | PagerDuty alert for on-call |
11. XTMS API Integration
The NexGO XTMS Cloud Open API (V1.9) provides full programmatic access for device provisioning.
Authentication
All XTMS API calls use SHA-256 signature-based authentication:
- Collect all request parameters (excluding
signature) - Sort by parameter name in ASCII/lexicographical order
- Concatenate as URL key-value pairs:
key1=value1&key2=value2... - Append the API key:
stringA + key - SHA-256 hash → uppercase hex string
Required per-request fields:
| Field | Description |
|---|---|
appId | Distributor identifier (provided by NexGO) |
key | API secret key (provided by NexGO) |
signatureMethod | Always SHA-256 |
signatureNonce | 13-digit timestamp (unique per request) |
timestamp | UTC time: yyyy-MM-dd'T'HH:mm:ssZ |
version | Always v1 |
XTMS app credentials are managed secrets, not an implementation blocker:
xtms-app-id and xtms-app-key are injected into merchant-onboarding as
XTMS_APP_ID and XTMS_KEY. Rotate them through the
secrets rotation runbook.
Provisioning Flow (XTMS_PUSH step detail)
The XTMS_PUSH job step executes the following XTMS API calls in sequence:
Step 1: Create XTMS Merchant
POST /openapi/merchant/add
Request:
{
"merchantName": "Store ABC",
"merchantNo": "MID_12345", // TransIT merchantId
"terminalNos": ["TID_001", "TID_002"] // TransIT terminal IDs
}
Response:
{ "status": 200, "detail": 10086 } // XTMS merchant ID
Error codes: 1005001 (merchant already exists), 1005003 (TID duplicated)
Step 2: Bind Device to Terminal
POST /openapi/terminal/bindMachine
Request:
{
"merchantNo": "MID_12345",
"sn": "N5-2024-001234", // Physical device serial
"terminalNo": "TID_001"
}
Response:
{ "status": 200, "detail": null }
Rules: One device → one terminal. Device must belong to our distributor account.
Error codes: 1008003 (terminal already bound), 1008004 (device already bound), 1007 (SN not owned)
Step 3: Create Parameter File with TransIT Credentials
POST /openapi/param/addParamFile
Request:
{
"fileName": "transit_creds_MID_12345_TID_001",
"remark": "TransIT credentials for merchant MID_12345",
"spcParam": "{\"TRANSIT_DEVICE_ID\":\"88700000123456\",\"TRANSIT_TXN_KEY\":\"encrypted_key_value\"}"
}
Response:
{
"status": 200,
"detail": {
"id": 695,
"fileName": "transit_creds_MID_12345_TID_001",
"pkey": "ebf6deaaa3933c1ffffdd7eba20883da" // Used for subsequent updates
}
}
SPC = Specific Parameter Configuration. Custom key-value pairs delivered to the SmartConnect app. The
isEncryption: 1flag on parameter items hides values in the XTMS UI.
Step 4: Push Parameters to Device
POST /openapi/paramPush/pushBySN
Request:
{
"snList": ["N5-2024-001234"],
"appPackageName": "com.nexgo.smartconnect", // SmartConnect package name
"paramId": 695 // Parameter file ID from step 3
}
Response:
{ "status": 200, "detail": null }
Rules: Max 5000 SNs per push. Creates async task — device must be online to receive.
Step 5: Monitor Push Status
POST /openapi/paramPush/getPushDetail
Request:
{
"pushId": 2,
"sn": "N5-2024-001234",
"page": 1,
"pageSize": 10
}
Response:
{
"status": 200,
"detail": {
"processingMachineCount": 0,
"successMachineCount": 1,
"failMachineCount": 0,
"pageData": {
"rows": [
{
"sn": "N5-2024-001234",
"state": 3, // 3 = Success
"updateTime": "2026-03-08T15:00:12Z"
}
]
}
}
}
Push states: 0 Not requested, 1 Requesting, 2 Downloading, 3 Success, 4 Failed, 5 Canceled, 9 Ignored
Additional XTMS Endpoints Used
| Endpoint | Method | Purpose |
|---|---|---|
/openapi/merchant/updateInfo | POST | Update merchant name/contact info |
/openapi/merchant/detail | POST | Get merchant details by ID |
/openapi/terminal/unboundMachine | POST | Unbind device from terminal (deprovisioning) |
/openapi/terminal/getList | POST | List terminals and binding status |
/openapi/param/specific/update | POST | Update SPC parameters (credential rotation) |
/openapi/paramPush/cancelBySn | POST | Cancel pending push for a device |
/openapi/paramPush/closeById | POST | Close a completed push task |
/openapi/paramPush/getPushListBySN | POST | Get all push tasks for a specific device |
XTMS Status Codes
| Code | Description |
|---|---|
| 200 | Success |
| 1001 | General failure |
| 1005 | Distributor does not exist or lacks API permissions |
| 1006 | Signature verification failed |
| 1007 | SN does not match distributor ownership |
| 1008 | No permission for this interface |
| 1005001 | Merchant already exists |
| 1005002 | Merchant does not belong to distributor |
| 1005003 | TID is duplicated |
| 1005004 | Terminal already bound to a device |
| 1008003 | Terminal already bound to another merchant terminal |
| 1008004 | Merchant terminal already bound to another device |
| 1008006 | No authority to bind device to this terminal |
| 9999 | Unknown error |
| -1 | System exception |
Easy Deploy (Alternative for Bulk Provisioning)
XTMS Easy Deploy (V1.8+) bundles APP + PARAM + OTA + RKI tasks into a single template. Useful for fleet provisioning:
POST /openapi/easydpl/template/create // Create template (max 10 tasks)
POST /openapi/easydpl/push/create // Push template to devices by SN
POST /openapi/easydpl/push/list // List push tasks
POST /openapi/easydpl/push/detail // Track per-device status
Consider using Easy Deploy for initial fleet rollout (SmartConnect app + TransIT credentials + firmware in one push).
Gateway vs NexGO Cloud / MDM Boundary
Gateway uses XTMS for merchant/device provisioning, terminal binding and unbinding, SmartConnect SPC parameter creation/update, TransIT credential pushes, credential rotation, and push-status inspection. The Android SDK owns the SmartConnect runtime protocol and exposes Gateway runtime commands for runtime wipe, credential rotation, reconciliation trigger, SDK state reset, payment-runtime reprovision, SmartConnect prepare, and SmartConnect status.
XTMS app deployment, firmware/OTA, RKI/certificate pushes, Easy Deploy template administration, and other fleet MDM functions remain NexGO Cloud / operations scope unless a specific workflow is promoted into the Gateway runtime-command surface. POS applications should not call XTMS directly.
| Key | Label | Secret |
|---|---|---|
PROCESSOR | TSYS | No |
MERCHANT_ID | TransIT Merchant ID (MID) | No |
USER_ID | TransIT User ID | No |
PASSWORD | Password | Yes |
DEVICE_ID | TransIT Device ID | No |
FCS_ID | FCS ID (Optional) | No |
HOST_URL | Host URL | No |
Manual copy workflow:
- Provisioning completes
TRANSIT_ACTIVATIONandCREDENTIAL_STORAGE. - Authorized support/admin opens the manual Nexgo credential package in the gateway-controlled workflow.
- UI displays masked values with explicit copy controls for the selected Nexgo device.
- Operator copies the values onto the device using the approved Nexgo device credential entry path.
- Operator confirms completion in the gateway workflow.
- Audit log records who viewed the raw package and when manual copy was confirmed.
This preserves the audit trail and keeps raw credentials inside the CDE boundary. This mode is a degraded fallback for devices that cannot receive credentials through the API push path.