> ## Documentation Index
> Fetch the complete documentation index at: https://docs.basaltic.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Issuing a certificate

> The DNS challenge start to finish, who publishes the CNAME, wildcards, and choosing a key algorithm.

## Issuing a certificate

Issuance is asynchronous. `POST /v1/certificates` answers **`202`** with the
certificate in `pending` and an **empty** `challenges` list — the challenges are
planned by the issuance workflow just after the row is created, not by the call
that created it.

<Steps>
  <Step title="Create the certificate">
    <Tabs>
      <Tab title="Console">
        Go to **Certificates** and choose **Create Certificate**. Give it a
        **Name**, add each **Domain**, and leave the source on **Auto-issue
        via DNS challenge**.

        The certificate lands in the list straight away, and the detail page
        shows **Configure DNS to complete certificate issuance** with the
        records to publish.
      </Tab>

      <Tab title="API">
        ```bash theme={null}
        POST https://certificate.sa-saopaulo-1.basaltic.sh/v1/certificates
        {
          "name": "prod-frontend",
          "domains": ["example.com", "www.example.com"]
        }
        ```
      </Tab>

      <Tab title="CLI">
        ```bash theme={null}
        basaltic certificate create \
          --name prod-frontend \
          --domains example.com,www.example.com
        ```
      </Tab>

      <Tab title="Go">
        ```go theme={null}
        cfg, err := basaltic.NewConfig(ctx,
            basaltic.WithClientCredentials(os.Getenv("BASALTIC_ACCESS_KEY_ID"), os.Getenv("BASALTIC_SECRET_ACCESS_KEY")),
            basaltic.WithRegion("sa-saopaulo-1"),
        )
        if err != nil {
            log.Fatal(err)
        }

        crt, err := certificate.New(cfg).CreateCertificate(ctx, &certificate.CertificateIssueRequest{
            Name:    "prod-frontend",
            Domains: []string{"example.com", "www.example.com"},
        })
        ```

        Certificates are regional, so the config needs a region.
      </Tab>
    </Tabs>

    `name` is unique per account and lands in the CRN, so it has to be
    URL-safe — letters, digits, dot, dash, underscore.
  </Step>

  <Step title="Poll until the challenges appear">
    ```bash theme={null}
    GET /v1/certificates/{certificate_id}
    ```

    The status moves to `pending_dns` and `challenges` grows one entry per
    domain, each carrying `cname_record_name`, `expected_cname` and `our_dns`.

    <Warning>
      Do not read `challenges` from the create response — it is always empty
      there. Poll the certificate.
    </Warning>
  </Step>

  <Step title="Publish the CNAME">
    Each challenge needs `_acme-challenge.<domain>` pointing at that
    challenge's `expected_cname`. Whether you do anything here depends on who
    hosts the zone — see below.
  </Step>

  <Step title="Wait for active">
    Each challenge flips `verified: true` as its CNAME resolves. Once every
    challenge is verified and signing completes, the certificate becomes
    `active` and `certificate_pem`, `fingerprint`, `issued_at` and
    `expires_at` are populated.
  </Step>
</Steps>

### Who publishes the CNAME

<Tabs>
  <Tab title="Domain on Basaltic DNS">
    The challenge comes back with `our_dns: true` and **the CNAME has already
    been created for you**. There is nothing to do but poll until `verified`
    turns true.
  </Tab>

  <Tab title="Domain hosted elsewhere">
    The challenge comes back with `our_dns: false`. Add the record at your
    registrar, exactly as the challenge names it:

    ```dns theme={null}
    _acme-challenge.example.com.  CNAME  <expected_cname>
    ```

    Take `expected_cname` from the challenge rather than copying it from
    anywhere else — it is per-order, and the target is where the validation
    TXT gets published during issuance.

    <Note>
      The delegation is one-time work per domain, not per issuance. Leave the
      CNAME in place and renewals validate without you touching DNS again.
    </Note>
  </Tab>
</Tabs>

### Wildcards

A wildcard SAN validates at its **parent** name, not at the literal SAN — this
is [RFC 8555 §8.4](https://datatracker.ietf.org/doc/html/rfc8555#section-8.4).
So a certificate for `*.example.com` needs:

```dns theme={null}
_acme-challenge.example.com.  CNAME  <expected_cname>
```

The challenge's `cname_record_name` already accounts for this; publish what it
says and the wildcard case takes care of itself.

<Warning>
  A wildcard order can only be signed by a wildcard-capable authority. If none
  is available the certificate fails rather than falling back to one that
  cannot issue it.
</Warning>

## Key algorithms

`key_algorithm` defaults to **`ecdsa-p256`** and cannot be changed after
creation — issue a new certificate to move to a different algorithm.

<Columns cols={2}>
  <Card title="ECDSA" icon="feather">
    `ecdsa-p256` (default), `ecdsa-p384`. Smaller keys, faster handshakes.
    Prefer these unless a client requires RSA.
  </Card>

  <Card title="RSA" icon="building">
    `rsa-2048`, `rsa-4096`. For older clients and appliances that will not
    negotiate an ECDSA chain.
  </Card>
</Columns>
