Skip to content

Maximize TLS lifetime with a re-issue cycle

If your product works with a one-year commercial term while the CA only issues certificates with a shorter maximum validity, you can now automate that lifecycle much more cleanly with the current regfish API.

The important change is that the model is now split cleanly: follow-up issuances on the same order use POST /tls/certificate/{certificate_id}/reissue, while the transition into the next contract period uses POST /tls/certificate with renewal_of_certificate_id.

The API now exposes the provider-side contract window through contract_valid_from and contract_valid_until. If your own commerce or billing logic has an additional lifecycle on top, you can still enrich the workflow with your own business dates.

  • an API key with access to TLS and DNS endpoints
  • the current certificate response, including contract_valid_until
  • optionally, an internally stored commercial end date if it differs from the provider-side contract window
  • an active certificate id that is currently deployed
  • a job or scheduler that can evaluate the workflow daily or multiple times per day
  • a fresh CSR for every follow-up issuance
  • a zone managed through Regfish DNS

Step 1: Place the initial issuance at the CA maximum validity

Section titled “Step 1: Place the initial issuance at the CA maximum validity”

Create the first issuance directly with the maximum publicly documented validity_days. In the current OpenAPI contract that maximum is 199.

Terminal-Fenster
curl --request POST \
--url 'https://api.regfish.com/tls/certificate' \
--header 'content-type: application/json' \
--header 'x-api-key: YOUR_API_KEY' \
--data '
{
"sku": "RapidSSL",
"common_name": "www.example.com",
"dns_names": ["api.example.com"],
"csr": "-----BEGIN CERTIFICATE REQUEST-----\nMIIC...\n-----END CERTIFICATE REQUEST-----",
"dcv_method": "dns-cname-token",
"validity_days": 199
}
'

Store your internal control record right away alongside the API response. The provider-side contract window can come from the API, while any extra commercial context can still come from your own system if needed.

{
"contract_valid_from": "2026-03-16T00:00:00Z",
"contract_valid_until": "2027-03-16T23:59:59Z",
"active_certificate_id": "7K9QW3M2ZT8HJ",
"sku": "RapidSSL",
"common_name": "www.example.com",
"dns_names": ["api.example.com"],
"dcv_method": "dns-cname-token"
}

Step 2: Finish the first issuance and store the actual validity

Section titled “Step 2: Finish the first issuance and store the actual validity”

Take the records returned in validation.dns_records and create them in DNS. After that, poll the order until valid_until and certificate_pem_available are present.

Terminal-Fenster
curl --request POST \
--url 'https://api.regfish.com/dns/rr' \
--header 'content-type: application/json' \
--header 'x-api-key: YOUR_API_KEY' \
--data '
{
"type": "CNAME",
"name": "_dnsauth.example.com",
"data": "0123456789abcdef.dcv.digicert.com.",
"ttl": 300
}
'
Terminal-Fenster
curl --request GET \
--url 'https://api.regfish.com/tls/certificate/7K9QW3M2ZT8HJ' \
--header 'x-api-key: YOUR_API_KEY'

From the issued response, store at least:

  • contract_valid_from
  • contract_valid_until
  • valid_from
  • valid_until
  • status
  • certificate_pem_available

The efficient lifecycle minimizes overlap, so it waits until shortly before the current certificate expires. At the same time, a re-issue should no longer be triggered once the remaining provider-side contract term is effectively used up.

A simple decision model looks like this:

reissue_lead_days = 7
safety_days = 2
days_until_expiry = floor((valid_until - now) / 86400)
days_until_contract_end = floor((contract_valid_until - now) / 86400)
if days_until_contract_end <= reissue_lead_days + safety_days:
action = "renew-next-term"
elif days_until_expiry > reissue_lead_days:
action = "wait"
else:
action = "reissue-now"

The important parts are:

  • only re-issue shortly before valid_until so you do not waste coverage
  • once the commercial remaining term is effectively used up, do not trigger one more re-issue; start the next renewal as a new order
  • the main optimization still comes from the trigger timing; use validity_days on re-issue only when you intentionally want to request a shorter replacement lifetime for eligible multi-year orders
  • use contract_valid_until from the API as the baseline contract boundary; add your own commercial cutoff only if your business model needs it

Step 4: Trigger the re-issue on the same order

Section titled “Step 4: Trigger the re-issue on the same order”

When the decision model returns reissue-now, trigger the re-issue directly on the existing certificate id. This is exactly where the new endpoint is a better fit than the older model of creating a separate certificate order.

Terminal-Fenster
curl --request POST \
--url 'https://api.regfish.com/tls/certificate/7K9QW3M2ZT8HJ/reissue' \
--header 'content-type: application/json' \
--header 'x-api-key: YOUR_API_KEY' \
--data '
{
"csr": "-----BEGIN CERTIFICATE REQUEST-----\nMIIC...\n-----END CERTIFICATE REQUEST-----",
"dcv_method": "dns-cname-token",
"comments": "Scheduled reissue near certificate expiry",
"validity_days": 90
}
'

For this re-issue, prefer a new key and therefore a new CSR. Only send validity_days when you intentionally want a shorter replacement certificate and the underlying multi-year order supports it.

Do not assume that the old DCV token remains valid. Read the new record from response.reissue.validation.dns_records and update the existing _dnsauth record preferably through PATCH /dns/rr.

Terminal-Fenster
curl --request PATCH \
--url 'https://api.regfish.com/dns/rr' \
--header 'content-type: application/json' \
--header 'x-api-key: YOUR_API_KEY' \
--data '
{
"type": "CNAME",
"name": "_dnsauth.example.com",
"data": "fedcba9876543210.dcv.digicert.com.",
"ttl": 300
}
'

If the record does not exist yet, the workflow falls back to POST /dns/rr for that step.

Step 6: Promote the new certificate and advance internal state

Section titled “Step 6: Promote the new certificate and advance internal state”

Once the re-issue has been issued, download the new certificate through the same certificate id and advance your internal control state.

Terminal-Fenster
curl --request GET \
--url 'https://api.regfish.com/tls/certificate/7K9QW3M2ZT8HJ' \
--header 'x-api-key: YOUR_API_KEY'
Terminal-Fenster
curl --request GET \
--url 'https://api.regfish.com/tls/certificate/7K9QW3M2ZT8HJ/download/pem' \
--header 'x-api-key: YOUR_API_KEY' \
--output 'certificate-7K9QW3M2ZT8HJ.pem'

After that, persist at least:

  • active_certificate_id = 7K9QW3M2ZT8HJ
  • the new valid_until
  • reissue.requested_at or your own timestamp of the last follow-up issuance

In a normal re-issue flow, you usually do not need to revoke the old certificate. After the new deployment is complete, the old certificate can simply expire naturally.

Step 7: Start the next contract period as an explicit renewal

Section titled “Step 7: Start the next contract period as an explicit renewal”

When the decision model returns renew-next-term, do not place another follow-up issuance on the same order. Instead, create a new order and explicitly mark it as a renewal of the current certificate.

Terminal-Fenster
curl --request POST \
--url 'https://api.regfish.com/tls/certificate' \
--header 'content-type: application/json' \
--header 'x-api-key: YOUR_API_KEY' \
--data '
{
"sku": "RapidSSL",
"common_name": "www.example.com",
"dns_names": ["api.example.com"],
"csr": "-----BEGIN CERTIFICATE REQUEST-----\nMIIC...NEXT...\n-----END CERTIFICATE REQUEST-----",
"dcv_method": "dns-cname-token",
"renewal_of_certificate_id": "7K9QW3M2ZT8HJ",
"validity_days": 199
}
'

This request creates a new order with a new certificate id. That is exactly why it is not a re-issue, but the start of the next contract or billing cycle. After that, treat the response like any other new order: apply the returned DCV record, poll the new order, download the certificate through the new certificate id, and persist the mapping renewed_from_certificate_id -> new_certificate_id.

For renewals, remember that validity_days is still only the purchased base order validity. Once the order has been issued, use valid_until as the authoritative lifetime and persist renewal_bonus_days when the provider confirms extra carried-over validity.

  • make re-issue jobs idempotent, for example per contract and target generation
  • generate the next CSR before the re-issue window so key creation never blocks issuance
  • keep DNS TTLs short so updated DCV tokens take effect quickly
  • keep a small buffer between ordering and the expected deployment time
  • use renewal_of_certificate_id explicitly when moving into the next contract period instead of creating a completely unrelated new order

With the current regfish API, this lifecycle can now be automated much more cleanly: the initial issuance runs through create-certificate, later follow-up issuances on the same order run through reissue-certificate, and the next contract period starts again through create-certificate with renewal_of_certificate_id. The API now also exposes the provider-side contract window directly, while any additional commercial logic can still live in your own system if needed.