Skip to Content
API Integration Guide

Veil Backend API Integration Guide

This document describes the backend HTTP API for integrating applications, issuers, and protocol services with the Veil credit scoring protocol on Midnight preprod.

Base URL

Local development:

http://localhost:3001/api/v1

Production and shared environments should expose the same versioned path:

https://<backend-host>/api/v1

Integration Flow

  1. Check backend readiness with GET /health.
  2. Create or update protocol state by calling the relevant resource endpoint.
  3. Transaction endpoints return 202 Accepted with a queued job record.
  4. Read the returned id.
  5. Poll GET /jobs/{jobId} until the job status is succeeded or failed.

The backend submits Midnight contract transactions asynchronously because proof generation and chain confirmation can take longer than a normal HTTP request lifecycle.

Data Formats

All requests and responses use JSON.

Hex-encoded byte fields are sent as strings without a required 0x prefix. Values that map to Compact Uint or JavaScript bigint are returned as decimal strings in JSON responses. Request integer fields can be sent as JSON numbers or decimal strings; decimal strings are recommended for large values.

Common byte fields:

FieldTypeDescription
userPkhex stringUser public key or Veil identity public key expected by the contract circuit.
issuerPkhex stringIssuer or protocol public key submitting or verifying data.
eventIdhex string, optionalUnique 32-byte id for replay protection. If omitted, the backend generates one.
challengehex string, optionalUnique 32-byte verification challenge. If omitted, the backend generates one.
ownershipSecrethex stringSecret used by the PoT NFT verification circuit.

Job Object

Transaction endpoints return the same job shape as GET /jobs/{jobId}.

{ "id": "6c8cfa3d-6fd4-458c-8ad9-0c58dcbfef69", "name": "Scoring_createScoreEntry", "status": "queued", "createdAt": "2026-04-27T10:21:00.000Z", "updatedAt": "2026-04-27T10:21:00.000Z" }

Possible statuses:

StatusMeaning
queuedThe transaction is waiting to be processed.
runningThe backend is generating proof data and submitting the transaction.
succeededThe contract call completed. The result field contains transaction metadata.
failedThe contract call failed. The error field contains the failure message.

Successful job result example:

{ "id": "6c8cfa3d-6fd4-458c-8ad9-0c58dcbfef69", "name": "Scoring_createScoreEntry", "status": "succeeded", "createdAt": "2026-04-27T10:21:00.000Z", "updatedAt": "2026-04-27T10:21:18.000Z", "startedAt": "2026-04-27T10:21:01.000Z", "finishedAt": "2026-04-27T10:21:18.000Z", "result": { "circuit": "Scoring_createScoreEntry", "contractAddress": "0200...", "txHash": "..." } }

Errors

Validation and lookup errors use this shape:

{ "success": false, "message": "Job not found" }

Common status codes:

StatusMeaning
200 OKRead request succeeded.
201 CreatedChallenge was generated.
202 AcceptedTransaction job was queued.
400 Bad RequestRequest body or parameters are invalid.
404 Not FoundRequested resource does not exist.

Endpoints

Health Check

GET /health

Response:

{ "success": true, "service": "veil-backend", "version": "v1" }

Generate Verification Challenge

POST /challenges

Creates a fresh challenge for PoT NFT verification. The challenge expires after roughly 60 seconds.

Response 201 Created:

{ "challenge": "8f6c...", "challengeExpiresAt": "1777285341000" }

Get Job

GET /jobs/{jobId}

Path parameters:

ParameterTypeDescription
jobIdUUID stringJob id returned by a transaction endpoint.

Response 200 OK: a job object.

Create Score Entry

POST /score-entries

Queues Scoring_createScoreEntry.

Request:

{ "userPk": "aabbcc..." }

Response 202 Accepted: queued job object.

Verify PoT NFT

POST /pot-nft/verifications

Queues NFT_verifyPoTNFT. Use POST /challenges first when the client needs to display or sign a challenge before verification.

Request:

{ "issuerPk": "112233...", "userPk": "aabbcc...", "challenge": "8f6c...", "challengeExpiresAt": "1777285341000", "ownershipSecret": "998877..." }

Optional fields:

FieldDefault
challengeBackend-generated 32-byte random value.
challengeExpiresAtCurrent server time plus 60 seconds, in Unix milliseconds.

Response 202 Accepted: queued job object.

Submit Repayment Event

POST /scoring-events/repayments

Queues Scoring_submitRepaymentEvent.

Request:

{ "userPk": "aabbcc...", "issuerPk": "112233...", "paidOnTimeFlag": "1", "amountWeight": "75", "eventEpoch": "1777285281000", "eventId": "0f0e0d..." }

eventId is optional. If omitted, the backend generates a unique 32-byte id.

Response 202 Accepted: queued job object.

Submit Liquidation Event

POST /scoring-events/liquidations

Queues Scoring_submitLiquidationEvent.

Request:

{ "userPk": "aabbcc...", "issuerPk": "112233...", "severity": "3", "eventEpoch": "1777285281000", "eventId": "0f0e0d..." }

eventId is optional.

Response 202 Accepted: queued job object.

Submit Protocol Usage Event

POST /scoring-events/protocol-usage

Queues Scoring_submitProtocolUsageEvent.

Request:

{ "userPk": "aabbcc...", "issuerPk": "112233...", "protocolId": "556677...", "eventEpoch": "1777285281000" }

Response 202 Accepted: queued job object.

Submit Debt State Event

POST /scoring-events/debt-states

Queues Scoring_submitDebtStateEvent.

Request:

{ "userPk": "aabbcc...", "issuerPk": "112233...", "activeDebtFlag": "1", "riskBand": "2", "eventEpoch": "1777285281000", "eventId": "0f0e0d..." }

eventId is optional.

Response 202 Accepted: queued job object.

Curl Examples

Create a score entry:

curl -X POST http://localhost:3001/api/v1/score-entries \ -H 'Content-Type: application/json' \ -d '{"userPk":"aabbcc"}'

Poll the queued transaction:

curl http://localhost:3001/api/v1/jobs/6c8cfa3d-6fd4-458c-8ad9-0c58dcbfef69

Generate a verification challenge:

curl -X POST http://localhost:3001/api/v1/challenges
Last updated on