# VAT API integration kit

These are server-side examples, not an official SDK. Node 22.18+ can run client.ts directly. Python 3.10+ can use client.py without extra packages.

Use your real key only with https://vat.limetip.com. Never embed it in browser code. A company administrator creates keys at https://vat.limetip.com/developers. The public guide is https://vat.limetip.com/docs.

## Free connection check

TypeScript:

```ts
import { getAccount, runOperation } from './client.ts'
const options = {
  baseUrl: 'https://vat.limetip.com',
  apiKey: process.env.LIMETIP_API_KEY!,
}
const account = await getAccount(options) // free
if (account.status !== 'ready')
  throw new Error('Ask your administrator to activate access')
```

Python:

```python
import os
from client import get_account, run_operation
base = 'https://vat.limetip.com'
key = os.environ['LIMETIP_API_KEY']
account = get_account(base, key)  # free
if account['status'] != 'ready':
    raise RuntimeError('Ask your administrator to activate access')
```

## Run a paid operation

The example clients generate an operation ID before their retry loop and reuse it automatically. A normal call only needs a mode and VAT number.

```ts
const operation = { mode: 'registry', vatNumber: 'SE123456789001' }
const response = await runOperation(options, operation)
if (response.result.registration_status === 'valid') {
  // Confirmed registration. Company name/address may still be null.
} else if (response.result.registration_status === 'invalid') {
  // Registry did not confirm active registration.
} else {
  // Not checked by the registry. Format acceptance is not proof of registration.
}
```

```python
operation = {'mode': 'registry', 'vat_number': 'SE123456789001'}
response = run_operation(base, key, operation)
registered = response['result']['registration_status'] == 'valid'
```

One completed format, registry or lookup operation consumes one credit, including negative results. Registry checks already return available company details, so do not automatically follow one with a lookup. Replays return the original result with zero additional charge.

The examples use bounded retries for transport errors and transient HTTP failures. Error objects expose status, stable code and a support request ID. Do not retry 4xx blindly. Expiry, missing permissions and no credits need explicit action.

For recovery after a worker or process restart, save an ID with your durable job before sending and pass it as the optional `id` field. Load that same job for every later attempt. A replacement API key cannot replay the original credential's operation.

```ts
const operation = await jobs.load(jobId) // {id, mode, vatNumber}
const response = await runOperation(options, operation)
```

```python
operation = jobs.load(job_id)  # id, mode, vat_number
response = run_operation(base, key, operation)
```

## Deterministic local testing

Download mock-server.mjs and fixtures.json into the same directory. Use a dummy key with this mock, never a production secret. This process binds only to your loopback interface, never contacts a registry and consumes no credits.

```bash
SCENARIO=valid node mock-server.mjs
```

Point the example client at http://127.0.0.1:8099 with apiKey/mock key `mock-not-a-real-key`. Supported scenarios: valid, invalid, no-company-details, no-credits, unsupported, unavailable, invalid-key, malformed, inactive, replay, timeout-after-completion.

`timeout-after-completion` records the result and drops the first connection. Retrying the same ID returns it with replayed=true and charged_credits=0. This verifies that your code does not create a new paid operation after an ambiguous response. Mock data is fictional and is never evidence of real VAT registration.

## Environment separation

Keep separate secrets for local mocks and production. An internal LimeTip development instance is not a customer sandbox. The mock does not grant production credits. Public API keys are intended for servers; browser-to-API calls are not the supported integration path.

### Run against the mock

From this downloaded directory, start the server in one terminal:

```bash
SCENARIO=timeout-after-completion node mock-server.mjs
```

In another terminal, run this complete Node example. The client creates and reuses the ID automatically. Retrying after the dropped response returns the saved mock result with zero additional credits.

```bash
node --input-type=module -e '
import {runOperation} from "./client.ts";
const operation = {mode:"registry", vatNumber:"SE123456789001"};
console.log(await runOperation({baseUrl:"http://127.0.0.1:8099",apiKey:"mock-only"},operation));
'
```

Or use Python:

```bash
python3 - <<'PYTHON'
from client import run_operation
operation = {"mode":"registry", "vat_number":"SE123456789001"}
print(run_operation("http://127.0.0.1:8099", "mock-only", operation))
PYTHON
```

The clients allow three attempts by default. They honor `Retry-After` in seconds or HTTP-date form. A requested wait longer than 60 seconds ends automatic retries. Durable jobs should supply their saved ID when they schedule recovery later. Python also retries truncated HTTP responses. The mock binds replays to the same dummy credential, matching the real API's rotation boundary.
