Quick Start Guide
=================

This guide walks through obtaining a certificate using ACMEOW.

Prerequisites
-------------

Before starting, you need:

1. A domain name you control
2. Access to create DNS TXT records for your domain
3. Python 3.10 or later

Basic Workflow
--------------

The certificate issuance process follows these steps:

1. Create an ACME client and account
2. Create a certificate order
3. Complete domain validation challenges
4. Finalize the order and download the certificate

Step 1: Create Client and Account
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: python

   from pathlib import Path
   from acmeow import AcmeClient

   # Create client (use staging for testing!)
   client = AcmeClient(
       server_url="https://acme-staging-v02.api.letsencrypt.org/directory",
       email="admin@example.com",
       storage_path=Path("./acme_data"),
   )

   # Create or retrieve account
   client.create_account()

.. warning::
   Use the **staging** server for testing to avoid rate limits.
   Switch to the production server only when ready.

Step 2: Create Certificate Order
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: python

   from acmeow import Identifier

   # Order certificate for one or more domains
   order = client.create_order([
       Identifier.dns("example.com"),
       Identifier.dns("www.example.com"),
   ])

Step 3: Complete Challenges
~~~~~~~~~~~~~~~~~~~~~~~~~~~

For DNS-01 challenges (recommended for wildcards):

.. code-block:: python

   from acmeow import CallbackDnsHandler, ChallengeType

   def create_txt_record(domain: str, record_name: str, value: str) -> None:
       # record_name is "_acme-challenge.example.com"
       # value is the TXT record content
       print(f"Create TXT record: {record_name} = {value}")
       # Use your DNS provider's API here

   def delete_txt_record(domain: str, record_name: str) -> None:
       print(f"Delete TXT record: {record_name}")
       # Use your DNS provider's API here

   handler = CallbackDnsHandler(
       create_record=create_txt_record,
       delete_record=delete_txt_record,
       propagation_delay=120,  # Wait for DNS propagation
   )

   client.complete_challenges(handler, ChallengeType.DNS)

Step 4: Finalize and Get Certificate
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: python

   from acmeow import KeyType

   # Generate key and submit CSR
   client.finalize_order(KeyType.EC256)

   # Download certificate
   cert_pem, key_pem = client.get_certificate()

   # Save to files
   Path("certificate.pem").write_text(cert_pem)
   Path("private_key.pem").write_text(key_pem)

Using an External CSR
~~~~~~~~~~~~~~~~~~~~~

If you manage your own private key (e.g., from a hardware security module or
an external tool), you can pass a pre-generated CSR instead of having ACMEOW
create one:

.. code-block:: python

   from cryptography import x509
   from cryptography.hazmat.primitives import hashes, serialization
   from cryptography.hazmat.primitives.asymmetric import ec
   from cryptography.x509.oid import NameOID

   # Generate key and CSR externally
   my_key = ec.generate_private_key(ec.SECP256R1())
   csr = (
       x509.CertificateSigningRequestBuilder()
       .subject_name(x509.Name([
           x509.NameAttribute(NameOID.COMMON_NAME, "example.com"),
       ]))
       .add_extension(
           x509.SubjectAlternativeName([x509.DNSName("example.com")]),
           critical=False,
       )
       .sign(my_key, hashes.SHA256())
   )
   csr_pem = csr.public_bytes(serialization.Encoding.PEM)

   # Finalize with external CSR — no key is generated or stored by ACMEOW
   client.finalize_order(csr=csr_pem)

   # key_pem is None because the key was not managed by ACMEOW
   cert_pem, _ = client.get_certificate()

Both PEM (``str`` or ``bytes``) and DER (``bytes``) encoded CSRs are accepted.
When a CSR is provided, the ``key_type`` and ``common_name`` parameters are
ignored.

Complete Example
----------------

.. code-block:: python

   from pathlib import Path
   from acmeow import (
       AcmeClient, Identifier, KeyType,
       CallbackDnsHandler, ChallengeType,
   )

   # Initialize
   client = AcmeClient(
       server_url="https://acme-staging-v02.api.letsencrypt.org/directory",
       email="admin@example.com",
       storage_path=Path("./acme_data"),
   )

   # Account
   client.create_account()

   # Order
   order = client.create_order([Identifier.dns("example.com")])

   # Challenges
   def create_record(domain, name, value):
       print(f"CREATE: {name} TXT {value}")
       input("Press Enter when record is created...")

   def delete_record(domain, name):
       print(f"DELETE: {name}")

   handler = CallbackDnsHandler(create_record, delete_record)
   client.complete_challenges(handler, ChallengeType.DNS)

   # Finalize
   client.finalize_order(KeyType.EC256)
   cert_pem, key_pem = client.get_certificate()

   print("Certificate obtained successfully!")

ACME Servers
------------

+---------------+----------------------------------------------------------+
| CA            | Server URL                                               |
+===============+==========================================================+
| Let's Encrypt | ``https://acme-v02.api.letsencrypt.org/directory``       |
| (Production)  |                                                          |
+---------------+----------------------------------------------------------+
| Let's Encrypt | ``https://acme-staging-v02.api.letsencrypt.org/directory``|
| (Staging)     |                                                          |
+---------------+----------------------------------------------------------+
| ZeroSSL       | ``https://acme.zerossl.com/v2/DV90``                     |
+---------------+----------------------------------------------------------+
| Buypass       | ``https://api.buypass.com/acme/directory``               |
+---------------+----------------------------------------------------------+
