Select programming language for code examples


linkForgot password

Request a password reset for a user. When the user does not already have a password, they will be invited to set a password. This will send an email to the user, if it is a valid email address that exists in our system. The email will contain a link leading to a password reset form securely hosted by Keygen. To send a customized email, see below.

When the account is protected, and the user does not yet have a password set, they will not be able to set their initial password. Passwordless users are considered "managed" users, and depending on whether or not the account is protected, they may not have permission to set a password.

To work around this, you may do one of the following:

  1. Set a temporary password on the user. You can do this when creating the user, or you can do this after the fact. Once a password has been set, the user is no longer considered "managed" and may reset their password normally.
  2. Set the account to unprotected. Though note what this entails — you may want to set all policies to protected to ensure certain actions can't be taken by users, such as license creation.

In most cases, we recommend #1.

If you would like to use custom branding or your own domain, you can set deliver = false and listen for the user.password-reset webhook which will contain the user data and meta containing the user's password reset token. You can use the password reset token to fulfill the reset through the password reset fulfillment endpoint.

For an example of self-hosting your password reset flow, please see this repo.


linkURL Parameters

  • link<account>


    The identifier (UUID) or slug of your Keygen account.




    The email of the user.

  • linkmeta.deliver


    Whether or not to email a password reset notification to the user. When false, you will need to listen for the user.password-reset webhook event and implement the fulfillment logic yourself.


A 202 Accepted response will be returned.

Upon error, an errors object will be returned along with an HTTP status code indicating the type of error. When an error occurs, the data property will not be included.


Example request

const fetch = require("node-fetch")
const response = await fetch("<account>/passwords", {
method: "POST",
headers: {
"Content-Type": "application/vnd.api+json",
"Accept": "application/vnd.api+json"
body: JSON.stringify({
"meta": {
"email": "[email protected]",
"deliver": false
import requests
import json
res =
"Content-Type": "application/vnd.api+json",
"Accept": "application/vnd.api+json"
"meta": {
"email": "[email protected]",
"deliver": false
import SwiftyJSON
import Alamofire
method: .post,
headers: [
"Content-Type": "application/vnd.api+json",
"Accept": "application/vnd.api+json"
parameters: [
"meta": [
"email": "[email protected]",
"deliver": false
encoding: JSONEncoding.default
).responseJSON { response in
let status = response.response?.statusCode
using RestSharp;
var client = new RestClient("<account>");
var request = new RestRequest("passwords", Method.POST);
request.AddHeader("Content-Type", "application/vnd.api+json");
request.AddHeader("Accept", "application/vnd.api+json");
request.AddJsonBody(new {
meta = new {
email = "[email protected]",
deliver = false
var response = client.Execute(request);
import com.mashape.unirest.http.exceptions.*
import com.mashape.unirest.http.*
import org.json.*
val body = JSONObject(mapOf(
"meta" to mapOf(
"email" to "[email protected]",
"deliver" to false
val res ="<account>/passwords")
.header("Content-Type", "application/vnd.api+json")
.header("Accept", "application/vnd.api+json")
import com.mashape.unirest.http.exceptions.*;
import com.mashape.unirest.http.*;
import org.json.*;
import static java.util.Map.ofEntries;
import static java.util.Map.entry;
JSONObject body = new JSONObject(ofEntries(
entry("meta", ofEntries(
entry("email", "[email protected]"),
entry("deliver", false)
HttpResponse<JsonNode> res ="<account>/passwords")
.header("Content-Type", "application/vnd.api+json")
.header("Accept", "application/vnd.api+json")
#include <iostream>
#include <string>
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
using namespace std;
using namespace web;
using namespace web::http;
using namespace web::http::client;
using namespace web::json;
using namespace utility;
http_client client("<account>");
http_request req;
value meta;
meta["email"] = value::string("[email protected]");
meta["deliver"] = value::boolean(false);
value body;
body["meta"] = meta;
req.headers().add("Content-Type", "application/vnd.api+json");
req.headers().add("Accept", "application/json");
.then([](http_response res) {
auto status = res.status_code();
curl -X POST<account>/passwords \
-H 'Content-Type: application/vnd.api+json' \
-H 'Accept: application/vnd.api+json' \
-d '{
"meta": {
"email": "[email protected]",
"deliver": false

Example response / 202 Accepted

No content