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

# Any other language

> There is no SDK to install. The OpenAPI document is the contract, and you can generate a client from it.

Outside TypeScript there is no hand-written SDK, and there does not need to be one. The
[OpenAPI document](/api-reference/introduction) is emitted from the running server, so a generated
client is as current as the reference on this site.

## The document

```text theme={null}
https://ownsi.dev/openapi/json
```

The same document backs every endpoint page under **Endpoints**, and can be downloaded from the
menu at the top of any of them.

<Note>
  The API is internal today — same origin, session cookie. A generated client works, but you have
  to bring your own session. See [Authentication](/api-reference/authentication).
</Note>

## Generating a client

<CodeGroup>
  ```bash Python theme={null}
  openapi-python-client generate --url https://ownsi.dev/openapi/json
  ```

  ```bash Go theme={null}
  oapi-codegen -package ownsi https://ownsi.dev/openapi/json > ownsi.go
  ```

  ```bash Rust theme={null}
  openapi-generator generate -i https://ownsi.dev/openapi/json -g rust -o ./ownsi
  ```

  ```bash Anything else theme={null}
  npx @openapitools/openapi-generator-cli generate \
    -i https://ownsi.dev/openapi/json \
    -g <your-language> -o ./ownsi
  ```
</CodeGroup>

<Warning>
  Most generators handle the request/response shapes fine but do not model `GET /api/zones/:name`
  as a stream — they will hand you the whole body at once, or nothing. If you need the frames as
  they arrive, read that one endpoint by hand: it is plain server-sent events over a normal
  response body.
</Warning>

## By hand

The whole API is JSON over HTTP with a cookie. There is nothing to install.

<CodeGroup>
  ```bash Read a zone theme={null}
  curl -N https://ownsi.dev/api/zones/acme.com
  ```

  ```bash Add the name theme={null}
  curl -X POST https://ownsi.dev/api/domains \
    -H "content-type: application/json" \
    -H "Idempotency-Key: $(uuidgen)" \
    -b "$SESSION_COOKIE" \
    -d '{"domain":"acme.com"}'
  ```

  ```bash Claim it theme={null}
  curl -X POST https://ownsi.dev/api/claims \
    -H "content-type: application/json" \
    -b "$SESSION_COOKIE" \
    -d "{\"domainId\":\"$DOMAIN_ID\"}"
  ```

  ```bash Read the claim theme={null}
  curl https://ownsi.dev/api/claims/$CLAIM_ID -b "$SESSION_COOKIE"
  ```

  ```bash Force a run theme={null}
  curl -X POST https://ownsi.dev/api/verifications/$VERIFICATION_ID/runs -b "$SESSION_COOKIE"
  ```
</CodeGroup>

## Two things to get right in any language

<AccordionGroup>
  <Accordion title="Narrow on the discriminant before reading the payload" icon="code-branch">
    `diagnosis.observed` has a different shape for each of the thirteen `code` values, and a zone
    frame's `data` has a different shape per `step`. In a language without unions, that is a switch
    on the tag before you touch the rest.

    ```python theme={null}
    match diagnosis["code"]:
        case "negative_cache":
            wait(diagnosis["observed"]["secondsRemaining"])
        case "record_at_apex":
            show(diagnosis["observed"]["name"], diagnosis["observed"]["value"])
        case _:
            show(diagnosis["fix"])
    ```

    Falling through to `fix` is always safe: every diagnosis has one.
  </Accordion>

  <Accordion title="Retry only what is worth retrying" icon="rotate">
    `unresolvable` (502) and `rate_limited` (429) are worth a backoff. Nothing else is — see
    [the table](/errors#which-ones-are-worth-retrying).

    On 429, honour `Retry-After`. Forcing runs in a loop does not make DNS answer faster; the
    verification's own `waitEstimate.secondsRemaining` is the honest interval.
  </Accordion>
</AccordionGroup>
