Skip to main content
The PoH issuer provides endpoints that issue proof-of-human (PoH) credentials. The main endpoint is credential refresh, which re-issues a PoH credential using a Personal Custody Package (PCP) or a credential-only refresh flow.
Base URL is environment-specific and served by the signup-service app-api. Contact your World ID point of contact for environment endpoints and access.
The refresh endpoint is intended for World ID v3 holders to obtain v4 PoH credentials. It is not a general re-issuance endpoint for v4 holders.

Credential refresh

method
POST
/api/v1/refresh
Content-Type: multipart/form-data

Request

Headers

HeaderTypeRequiredDescription
x-zkp-proofstringyesBase64-encoded ZKP string containing idCommitment and sub.

Query parameters

QueryTypeRequiredDescription
idCommstringyesUser identity commitment.

Form fields (always required)

FieldTypeRequiredDescription
substringyesUser account ID (hex with 0x prefix). Must match previous refreshes for this idComm.
encrypted_user_idstringnoTemporary field while operator rewards depend on it.

PCP form fields (required only when submitting a PCP)

Include all fields below when refreshing with a Personal Custody Package.
FieldTypeDescription
signup_idstringSignup ID.
signup_id_saltstringSignup ID salt.
orb_idstringOrb ID.
orb_id_saltstringOrb ID salt.
operator_idstringOperator ID.
operator_id_saltstringOperator ID salt.
signup_reasonstringSignup reason.
signup_reason_saltstringSignup reason salt.
timestampstringTimestamp.
timestamp_saltstringTimestamp salt.
software_versionstringSoftware version.
software_version_saltstringSoftware version salt.
orb_countrystringOrb country.
orb_country_saltstringOrb country salt.
iris_code_shares_0stringIris code share 0.
iris_code_shares_1stringIris code share 1.
iris_code_shares_2stringIris code share 2.
hashes.jsonfilePCP hashes JSON file.
hashes.signfilePCP hashes signature file.

Example (credential-only refresh)

curl -X POST "https://<app-api-host>/api/v1/refresh?idComm=0xabc123..." \
  -H "x-zkp-proof: <base64-zkp>" \
  -F "sub=0x1a2b3c"

Example (refresh with PCP)

curl -X POST "https://<app-api-host>/api/v1/refresh?idComm=0xabc123..." \
  -H "x-zkp-proof: <base64-zkp>" \
  -F "sub=0x1a2b3c" \
  -F "signup_id=signup_123" \
  -F "signup_id_salt=..." \
  -F "orb_id=orb_abc" \
  -F "orb_id_salt=..." \
  -F "operator_id=operator_123" \
  -F "operator_id_salt=..." \
  -F "signup_reason=..." \
  -F "signup_reason_salt=..." \
  -F "timestamp=1700000000" \
  -F "timestamp_salt=..." \
  -F "software_version=1.2.3" \
  -F "software_version_salt=..." \
  -F "orb_country=US" \
  -F "orb_country_salt=..." \
  -F "iris_code_shares_0=..." \
  -F "iris_code_shares_1=..." \
  -F "iris_code_shares_2=..." \
  -F "[email protected]" \
  -F "[email protected]"

Response

Success response

{
  "success": true,
  "credential": "<base64-credential>",
  "message": "Credential refreshed successfully"
}

Error responses

StatusErrorDescription
400INVALID_SUBsub is missing or invalid.
400SUB_MISMATCHsub does not match the one used in previous refreshes.
404NO_SIGNUP_RECORDNo enrollment record found. User must re-enroll at an Orb.
429RATE_LIMIT_EXCEEDEDRefresh rate limit exceeded for the current window.
503-Credential refresh is disabled.
If PCP validation fails, the endpoint returns an error status with PCP_VALIDATION_FAILED.

Credential object format

The credential response field is a base64-encoded JSON representation of the World ID Credential object defined in world-id-protocol/crates/primitives/src/credential.rs.

Example (decoded)

{
  "id": 123456789,
  "version": "V1",
  "issuer_schema_id": 42,
  "sub": "<field-element-hex>",
  "genesis_issued_at": 1733241600,
  "expires_at": 1764777600,
  "claims": ["<field-element-hex>", "<field-element-hex>", "<field-element-hex>"],
  "associated_data_hash": "<field-element-hex>",
  "signature": "<signature-hex>",
  "issuer": {
    "pk": ["<x-decimal>", "<y-decimal>"]
  }
}

Field definitions

FieldTypeDescription
iduint64Issuer-scoped reference identifier for the credential.
versionstringCredential version. Current value is V1.
issuer_schema_iduint64Identifier for the (issuer, schema) pair registered in CredentialSchemaIssuerRegistry.
subFieldElementBlinded subject identifier derived from the World ID leaf index and an issuer-specific blinding factor.
genesis_issued_atuint64Unix timestamp (seconds) of the first issuance of this credential.
expires_atuint64Unix timestamp (seconds) for expiration.
claimsFieldElement[]Up to 16 claim commitments. Unused indices are the zero field element.
associated_data_hashFieldElementPoseidon2 hash of issuer-defined associated data. The associated data itself is not included.
signaturestring64-byte compressed EdDSA signature over the credential hash, hex-encoded (128 hex chars, no 0x).
issuerEdDSAPublicKeyIssuer public key that signed the credential.

Field representations

  • FieldElement values (sub, claims, associated_data_hash) are hex strings with a 0x prefix and 64 hex characters.
  • Issuer public key (issuer.pk) is serialized as [x, y] decimal strings for BabyJubJub affine coordinates.
  • Signature is hex-encoded compressed bytes (no 0x prefix).

PoH credential semantics

  • The user first obtains an Orb credential (currently a PCP in v2.3 format).
  • claim[0] is a commitment to the Orb credential, currently H(hashes.json).
  • When refreshing without a PCP, claims[0] is derived from issuer-defined refresh data (a hash of idCommitment, sub, and a timestamp).
  • The PoH credential has no associated data, so associated_data_hash is the zero field element.
  • The PoH credential subject is blinded and differs from the Orb credential subject.
  • The issuer may require a proof for the requested sub to prevent bricking an identity.
These details are issuer-specific and may evolve as the protocol migrates to the World ID 4.0 credential format.

References