Skip to main content
This endpoint issues a new proof-of-human (PoH) credential to a holder of a valid World ID. It can re-verify with a Personal Custody Package (PCP) or issue a credential-only refresh when a PCP is not available.
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.

Endpoint

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 "hashes.json=@hashes.json" \
  -F "hashes.sign=@hashes.sign"

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.

Decoding

const decoded = JSON.parse(Buffer.from(credential, "base64").toString("utf8"));

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-specific claims

  • When refreshing with a PCP, claims[0] is derived from the PCP hashes.json bytes.
  • When refreshing without a PCP, claims[0] is derived from issuer-defined refresh data (a hash of idCommitment, sub, and a timestamp).
  • In both cases, associated_data_hash is instead empty, i.e. the zero field element

References