Stellar Integration
Individual Verifications on Stellar are recorded as SoulBound Tokens (SBTs) via Soroban smart contracts. This page covers everything you need to integrate Stellar-based verifications into your application.
Supported Verification Types
| Verification | Circuit ID | Verification URL |
|---|---|---|
| Government ID (KYC) | 0x729d660e1c02e4e419745e617d643f897a538673ccf1051e093bbfa58b0a120b | id.human.tech/gov-id  |
| Phone | 0xbce052cf723dca06a21bd3cf838bc518931730fb3db7859fc9cc86f0d5483495 | id.human.tech/phone  |
On EVM chains (Optimism, Base), attestations via Sign Protocol are the recommended integration. On Stellar, SBTs via Soroban are the current method.
SBT Contract
| Component | Value |
|---|---|
| Contract Address | CCNTHEVSWNDOQAMXXHFOLQIXWUINUPTJIM6AXFSKODNVXWA4N7XV3AI5 |
| Network | Stellar Mainnet (Public) |
| RPC URL | https://mainnet.sorobanrpc.com |
Source code: GitHub 
Querying SBTs
TypeScript (Off-chain)
Use the Stellar SDK to query a user’s SBT status off-chain:
import {
rpc,
TransactionBuilder,
Networks,
Contract,
scValToNative,
nativeToScVal,
} from '@stellar/stellar-sdk'
type StellarSbt = {
action_nullifier: bigint
circuit_id: bigint
expiry: bigint
id: bigint
minter: string
public_values: Array<bigint>
recipient: string
revoked: boolean
}
type StellarSbtStatus = 'valid' | 'expired' | 'revoked' | 'none'
const sorobanRpcUrl = 'https://mainnet.sorobanrpc.com'
const sbtContractAddress = 'CCNTHEVSWNDOQAMXXHFOLQIXWUINUPTJIM6AXFSKODNVXWA4N7XV3AI5'
async function getStellarSBT(
address: string,
circuitId: string
): Promise<{ sbt?: StellarSbt; status: StellarSbtStatus }> {
const sorobanServer = new rpc.Server(sorobanRpcUrl)
const userAccount = await sorobanServer.getAccount(address)
const contract = new Contract(sbtContractAddress)
const operation = contract.call(
'get_sbt',
nativeToScVal(address, { type: 'address' }),
nativeToScVal(circuitId, { type: 'u256' })
)
const transaction = new TransactionBuilder(userAccount, {
networkPassphrase: Networks.PUBLIC,
fee: '100',
})
.addOperation(operation)
.setTimeout(60)
.build()
const response = await sorobanServer.simulateTransaction(transaction)
if (rpc.Api.isSimulationSuccess(response)) {
const parsed = rpc.parseRawSimulation(response)
const sbt = scValToNative(parsed.result?.retval)
return { sbt, status: 'valid' }
}
const error = response.error
if (error?.includes('Error(Contract, #1)')) return { status: 'none' }
if (error?.includes('Error(Contract, #5)')) return { status: 'revoked' }
if (error?.includes('Error(Contract, #6)')) return { status: 'expired' }
throw new Error(`SBT query failed: ${error}`)
}SBT Status Codes
| Status | Description |
|---|---|
valid | SBT exists and is active |
expired | SBT has passed its expiration date (1 year from issuance) |
revoked | SBT has been revoked |
none | No SBT found for this address |
Circuit IDs
Use the appropriate circuit ID when querying SBTs for a specific verification type:
| Verification Type | Circuit ID |
|---|---|
| Government ID (KYC) | 0x729d660e1c02e4e419745e617d643f897a538673ccf1051e093bbfa58b0a120b |
| Phone | 0xbce052cf723dca06a21bd3cf838bc518931730fb3db7859fc9cc86f0d5483495 |
Additional Resources
Last updated on