Start the expiration sweep
Runs the stale-session expiry sweep for the caller’s organization. The service also runs this job on its own schedule across every organization; this endpoint is the operator-triggered form, narrowed to one tenant. The sweep reconciles applications that have sat in ID_VERIFICATION_PENDING past the provider submission window: a job the provider reports as final is completed, and one the provider no longer knows about is moved to EXPIRED — nothing is expired without asking the provider first. Authenticated with an internal user’s org-scoped bearer token and authorized by a WorkOS check for org:kyc.override:write on the caller’s own organization. The organization is resolved from the token; passing organization_id is rejected. The run is held to the same interval as the scheduled one — there is no force bypass — and each organization has its own lease and due-window, so a manual run neither blocks nor is blocked by the global schedule.
Authorization
oauth2 Create a client with POST /v1/oauth/clients, then exchange its credentials for an access token. AUTHORIZATION_CODE clients act on behalf of a signed-in user and always use PKCE; CLIENT_CREDENTIALS clients act as themselves. A client may only be granted scopes its creator already holds — read the grantable list from GET /v1/oauth/clients/scopes.
In: header
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/v1/internal/kyc/applications/expirations"{ "job": "KYC_STALE_SESSION_EXPIRY", "organization_id": "string", "started_at": "2026-06-04T10:20:00.000Z", "finished_at": "2026-06-04T10:20:00.000Z", "result": { "scanned": 12, "expired": 3, "completed": 1, "still_pending": 8, "failed": 0 }}{ "code": "INVALID_PARAMS", "description": "user_id must be a UUID", "identifier": "string", "invalid_params": [ { "path": "user_id", "reason": "must be a UUID", "sub_code": "string" } ]}{ "code": "INVALID_PARAMS", "description": "user_id must be a UUID", "identifier": "string", "invalid_params": [ { "path": "user_id", "reason": "must be a UUID", "sub_code": "string" } ]}{ "code": "INVALID_PARAMS", "description": "user_id must be a UUID", "identifier": "string", "invalid_params": [ { "path": "user_id", "reason": "must be a UUID", "sub_code": "string" } ]}{ "code": "INVALID_PARAMS", "description": "user_id must be a UUID", "identifier": "string", "invalid_params": [ { "path": "user_id", "reason": "must be a UUID", "sub_code": "string" } ]}{ "code": "INVALID_PARAMS", "description": "user_id must be a UUID", "identifier": "string", "invalid_params": [ { "path": "user_id", "reason": "must be a UUID", "sub_code": "string" } ]}{ "code": "INVALID_PARAMS", "description": "user_id must be a UUID", "identifier": "string", "invalid_params": [ { "path": "user_id", "reason": "must be a UUID", "sub_code": "string" } ]}Send the primary phone OTP POST
Sends or resends the owner-authorization or new-number OTP for the caller's primary-phone-number change. The `otp` of the response tells where it went. A user token calls this on behalf of the signed-in user. Returns 404 when the phone number is not a contact on the caller's profile, and 409 when the current-account state changed and the flow must restart.
Get a user’s status GET
Internal KYC status endpoint for backend, backoffice, and onboarding orchestration. The /v1/internal/kyc form is exposed on the shared API host; the /api/internal/kyc form remains available for cluster-local service calls. Authenticated with either a backend user bearer token or a WorkOS M2M token holding org:kyc.applications:read; returns the backend-compatible status DTO for a user. A machine caller must pass a non-empty organization_id naming the tenant to read; a user token may not pass it, since its organization comes from the token.