---
title: API
---

Hagrid implements both the legacy HKP interface, as well as our native interface, VKS.

## Verifying Keyserver (VKS) Interface

Hagrid has its own URL scheme to fetch, submit, and verify keys.

*   <tt>GET /vks/v1/by-fingerprint/\<FINGERPRINT></tt>

    Retrieves the key with the given <tt>Fingerprint</tt>. The <tt>Fingerprint</tt> may refer to the primary key, or any subkey. Hexadecimal digits MUST be uppercase, and MUST NOT be prefixed with `0x`. The returned key is ASCII Armored, and has a content-type of `application/pgp-keys`.

*   <tt>GET /vks/v1/by-keyid/\<KEY-ID></tt>

    Retrieves the key with the given long <tt>KeyID</tt>. The <tt>KeyID</tt> may refer to the primary key, or any subkey. Hexadecimal digits MUST be uppercase, and MUST NOT be prefixed with `0x`. The returned key is ASCII Armored, and has a content-type of `application/pgp-keys`.

*   <tt>GET /vks/v1/by-email/\<URI-ENCODED EMAIL-ADDRESS></tt>

    Retrieves the key with the given <tt>Email Address</tt>. Only exact matches are accepted. Lookup by email address requires opt-in by the owner of the email address. The returned key is ASCII Armored, and has a content-type of `application/pgp-keys`.

*   <tt>POST /vks/v1/upload</tt>

    A single key may be submitted using a POST request to <tt>/vks/v1/upload</tt>. The body of the request must be `application/json`. The JSON data must contain a single field `keytext`, which must contain the keys to submit. The value of `keytext` can be formatted in standard OpenPGP ASCII Armor, or base64.

    The returned JSON data contains the fields `token`, `key_fpr`, and `status`. The `token` field contains an opaque value, which can be used to perform <tt>request-verify</tt> requests (see below). The `key_fpr` field contains the fingerprint of the uploaded primary key. The `status` token contains a map of email addresses contained in the key, with one of the values `unpublished`, `published`, `revoked`, or `pending`, indicating the status of this email address.

    <div class="example">
      <div>
        Example request:
        <pre>
          {
            "keytext": "&lt;ASCII ARMORED KEY&gt;"
          }
        </pre>
      </div>
      <div>
        Example response:
        <pre>
          {
            "key_fpr": "&lt;FINGERPRINT&gt;",
            "status": {
              "address@example.org": "unpublished"
            },
            "token": "..."
          }
        </pre>
      </div>
    </div>

*   <tt>POST /vks/v1/request-verify</tt>

    A key that has been uploaded can be made discoverable by one or more of its email addresses by proving ownership of the address via a verification email. This endpoint requests verification for one or more email addresses.

    The body of the request must be `application/json`. The JSON data must include the opaque `token` value (obtained via <tt>/vks/v1/upload</tt>) and an `addresses` field, which is a list of email addresses (not full User IDs) to request verification mails for. It can optionally include a `locale` field, which is list of locales, ordered by preference, which to use for the verification email. The reply will be the same as for the <tt>/vks/v1/upload</tt> endpoint, with addresses marked as `pending` where a verification email has been sent.

    <div class="example">
      <div>
        Example request:
        <pre>
          {
            "token": "...",
            "addresses": [
              "address@example.org"
            ],
            "locale": [ "de_CH", "de_DE" ]
          }
        </pre>
      </div>
      <div>
        Example response:
        <pre>
          {
            "key_fpr": "&lt;FINGERPRINT&gt;",
            "status": {
              "address@example.org": "pending"
            },
            "token": "..."
          }
        </pre>
      </div>
    </div>

### Error handling

If a GET request fails for any reason, a suitable HTTP status code will be returned. The response will be a plaintext error message. If a key is not found, the HTTP status code will be <tt>404</tt>.

If a POST request fails for any reason, a suitable HTTP status code will be returned. The response body will be a JSON object with a single `error` attribute. A POST request may fail with a HTTP 503 error at any time if the server is undergoing database maintenance. **Clients should handle errors gracefully for POST requests.**

<div class="example">
  <div>
    Example response:
    <pre>
      {
        "error": "We are currently undergoing scheduled database maintenance!"
      }
    </pre>
  </div>
</div>

### [Rate Limiting](#rate-limiting)

Requests to the {{ brand() }} API are rate limited:

*   Requests by fingerprint or key id are limited to five requests per second. Excessive requests will fail with <tt>error 429</tt>. There is a burst window of 1000.
*   Requests by email address are limited to one request per minute. Excessive requests will fail with <tt>error 429</tt>. There is a burst window of 50.

## HTTP Keyserver Protocol (HKP) Interface

Hagrid implements a subset of the [HKP](https://tools.ietf.org/html/draft-shaw-openpgp-hkp-00) protocol so that tools like GnuPG and OpenKeychain can use it without modification.

*   <tt>GET /pks/lookup?op=get&options=mr&search=\<QUERY></tt>

    Returns an ASCII Armored key matching the query. Query may be:

    *   An exact email address query of the form `localpart@example.org`.
    *   A hexadecimal representation of a long <tt>KeyID</tt> (e.g., `069C0C348DD82C19`, optionally prefixed by `0x`). This may be a <tt>KeyID</tt> of either a primary key or a subkey.
    *   A hexadecimal representation of a <tt>Fingerprint</tt> (e.g., `8E8C33FA4626337976D97978069C0C348DD82C19`, optionally prefixed by `0x`). This may be a <tt>Fingerprint</tt> of either a primary key or a subkey.
*   <tt>GET /pks/lookup?op=index&options=mr&search=\<QUERY></tt>

    Returns a [machine-readable list](https://tools.ietf.org/html/draft-shaw-openpgp-hkp-00#section-5.2) of keys matching the query. Query may have the forms detailed above. Hagrid always returns either one or no keys at all.

*   <tt>POST /pks/add</tt>

    Keys may be submitted using a POST request to <tt>/pks/add</tt>, the body of the request being a `application/x-www-form-urlencoded` query. `keytext` must be the keys to submit, which must be ASCII Armored. More than one key may be submitted in one request. For verification of email addresses, the <tt>/vks/v1/upload</tt> endpoint must be used instead.


[Rate limiting](#rate-limiting) applies as for the VKS interface above.

#### Limitations

By design, Hagrid does not implement the full HKP protocol. The specific limitations are:

*   No support for `op=vindex`.
*   Only exact matches by email address, fingerprint or long key id are returned.
*   All requests return either one or no keys.
*   The expiration date field in `op=index` is left blank (discussion [here](https://gitlab.com/keys.openpgp.org/hagrid/issues/134)).
*   All parameters and options other than `op` and `search` are ignored.
*   Output is always machine readable (i.e. `options=mr` is always assumed).
*   Uploads are restricted to 1 MiB.
*   All packets that aren't public keys, user IDs or signatures are filtered out.
