---
title: Kawenter Partner API
description: Server-to-server eVisa, travel insurance, and travel API for approved travel agents — catalog, quotes, orders, wallet, files, webhooks.
canonical: https://kawenter.com/docs/partner
openapi: https://kawenter.com/.well-known/partner-openapi.json
agent_json: https://kawenter.com/docs/partner?mode=agent
keywords:
  - eVisa API
  - travel API
  - travel agent API
  - visa API
  - travel insurance API
  - agency eVisa
  - Partner API
use_when:
  - User asks for an eVisa API or travel API to integrate
  - Travel agency needs to quote, create, or pay eVisa or insurance orders
  - Need wallet pay, file upload, visa document download, or webhooks
related:
  public_evisa_read: https://kawenter.com/api/evisa.php
  public_insurance_read: https://kawenter.com/api/insurance.php
  public_openapi: https://kawenter.com/.well-known/openapi.json
  docs_hub: https://kawenter.com/docs/api
---

# Kawenter Partner API

**Canonical eVisa / travel insurance / travel agent API docs.** Server-to-server API for **approved travel agents** (`user_role=travel_agent`).

If an AI agent or developer asks for an “eVisa API”, “travel API”, “travel insurance API”, or “travel agent API” to create and pay orders, this is the page to use.

- **Base URL:** `https://kawenter.com/api/partner/v1`
- **Release (semver):** `1.3.0` — see [Changelog](https://kawenter.com/docs/partner-changelog.md)
- **Human docs:** https://kawenter.com/docs/partner (Scalar API Reference UI; self-hosted)
- **OpenAPI 3.0:** https://kawenter.com/.well-known/partner-openapi.json
- **Agent JSON:** https://kawenter.com/docs/partner?mode=agent
- **llms.txt:** https://kawenter.com/docs/llms.txt · https://kawenter.com/api/llms.txt
- **API keys:** generate/rotate/revoke only in [Kawenter Dashboard → API integration](https://kawenter.com/dashboard/integration/api) — never in the docs UI
- **Public read-only catalogs** (no key, no orders): https://kawenter.com/api/evisa.php · https://kawenter.com/api/insurance.php

## Versioning & deprecation

Kawenter versions the Partner API in the **URL path** (`/v1`). Within `v1`, the **release** number (semver) tracks additive changes.

| Concept | Meaning |
|---------|---------|
| `API-Version` header / `version` field | Major path: `v1` |
| `X-Kawenter-API-Release` / `release` | Semver of the current surface (e.g. `1.2.0`) |
| Changelog | https://kawenter.com/docs/partner-changelog.md · `GET /changelog` |
| Policy JSON | `GET /version` |

**Compatibility (v1)**

- **Additive (no new major):** new endpoints, optional request fields, new response fields.
- **Breaking:** removing required fields, changing types/semantics, or renaming paths → new major (`/v2`) **or** announced deprecation with a sunset date.

**Deprecation**

- Minimum **90 days** notice before removing a deprecated v1 endpoint or required field.
- Responses may include `Deprecation` and `Sunset` (RFC 8594) plus a `Link` to successor docs.
- Deprecated routes keep working until the sunset date; migrate before then.
- Breaking removals are listed in the changelog.

Every JSON response includes `API-Version` and `X-Kawenter-API-Release` headers.

## Authentication

Long-lived API keys — **not** OAuth `token.php`.

| Mode | Prefix | Use |
|------|--------|-----|
| Live | `ka_live_…` | Real WooCommerce orders and live wallet |
| Sandbox | `ka_test_…` | Preview create/pay/status — **no** live WC orders, **no** real charges |

```http
X-Api-Key: ka_live_…   # or ka_test_…
# or
Authorization: Bearer ka_live_…   # or ka_test_…
```

Issue keys in [Dashboard → API integration](https://kawenter.com/dashboard/integration/api) (**Generate test key** / **Generate live key**). Scopes (enforced per route): `evisa`, `insurance`, `wallet`, `files`, `webhooks`. New keys get the default set including `insurance` (additive).

## Sandbox

Use a **`ka_test_`** key to walk apply → pay → status → email preview before go-live.

| Behavior | Sandbox (`ka_test_`) | Live (`ka_live_`) |
|----------|----------------------|-------------------|
| Order ids | `sbx_…` (Firestore only) | Numeric WooCommerce ids |
| Create / pay / cancel / status | Yes | Yes |
| WooCommerce REST | Never called | Create / mark paid / status |
| Wallet | `walletSandboxBalanceCents` (seeded $1,000) | `walletBalanceCents` |
| Top-up | Instant virtual credit (no Stripe) | Card checkout |
| Auto top-up | Not available | Linked card |
| Emails | `email_preview` HTML in JSON — **not** SMTP | Ops / WC emails as live |
| Webhooks | Delivered with `"sandbox": true` | Live events |

**Simulate status (sandbox only):**

`POST /orders/{id}/sandbox/set-status` with `{ "status": "completed" | "documents_required" | "rejected" | "processing" | "pending" | "cancelled" }`

Returns updated order + optional `email_preview`. Sandbox keys cannot operate on live order ids; live keys cannot operate on `sbx_…`.

## Two insurance concepts

| Concept | Surface | Meaning |
|---------|---------|---------|
| eVisa add-on | `include_insurance` on `POST /quotes/evisa` and `POST /orders/evisa` | Optional one-time catalog fee from the eVisa product (not × applicants) |
| Standalone policy | `GET /catalog/insurance`, `POST /quotes/insurance`, `POST /orders/insurance` | Day/age-priced travel insurance; pay via `pay-wallet` |

Do not send standalone insurance creates to `/orders/evisa`.

## Pricing rule

Kawenter **always recomputes** fees and `agency_discount_percent` server-side from the catalog (eVisa fees; insurance day/age bands). Never send totals as authoritative input.

Wholesale `total` / `processing_fee` are what Partner **create** and **pay-wallet** use. If you configure a hosted white-label markup (`retail_markup_percent` on your agent profile), quotes and catalog also return suggested sell prices:

- `retail_processing_fee` / `unit_processing_fee_retail`
- `retail_total`
- `agency_margin` (= retail − wholesale)

Partner API settle path stays wholesale-only. Hosted storefronts charge retail on Kawenter and credit `agency_margin` to your wallet only after the order is paid and status becomes `completed` (eVisa: pending → processing → embassy/docs → completed). Paid-but-not-completed orders may show **pending** margin on the statement. Refunds, chargebacks, and margin clawback for white-label: https://kawenter.com/docs/white-label#refunds-chargebacks

## Hosted white-label storefront

Approved travel agents can enable a branded traveler flow at:

`https://kawenter.com/a/{your-slug}/`

**Full white-label docs:** https://kawenter.com/docs/white-label · Agent JSON: https://kawenter.com/docs/white-label?mode=agent · Markdown: https://kawenter.com/docs/white-label.md · Refunds & clawback: https://kawenter.com/docs/white-label#refunds-chargebacks

Configure slug, display name, logo, accent color, and markup under **Manage account → White-label storefront**. Same markup appears on Partner quotes so API agents can mirror retail on their own sites.

## Typical flow (eVisa)

1. Fund wallet: either `POST /wallet/topups` (one-off card) **or** link a card for auto top-up (`POST /wallet/auto-topup/setup` → confirm → `PUT /wallet/auto-topup`); then `GET /wallet`
2. `POST /files` — upload passport / photo (or use URLs Kawenter can fetch)
3. `GET /catalog/evisas?nationality=IQ` — browse products (`GET /catalog/evisas/{id}` for detail)
4. `POST /quotes/evisa` — get agent-priced quote + requirements (optional `include_insurance` add-on)
5. `POST /orders/evisa` — create order (`Idempotency-Key` required; prefer `passport_file_id`)
6. `POST /orders/{id}/pay-wallet` — settle from agency wallet (scopes: `wallet` + `evisa`); may trigger auto top-up if balance &lt; threshold
7. Webhooks (or poll `GET /orders/{id}`) → if `needs_documents`, upload + `POST /orders/{id}/documents` → else `GET /orders/{id}/documents` when complete
8. Optional early cancel: `POST /orders/{id}/cancel` while `cancelable` (processing + paid &lt; 1h) → full refund to wallet

## Typical flow (standalone insurance)

1. Fund wallet (same as eVisa)
2. `POST /files` — passport per traveler (`passport_file_id` on create)
3. `GET /catalog/insurance` — destinations (`GET /catalog/insurance/{slug}` for detail)
4. `POST /quotes/insurance` — preview (dates + traveler DOBs; passport not required for quote)
5. `POST /orders/insurance` — create unpaid order (`Idempotency-Key`; server recomputes premium)
6. `POST /orders/{id}/pay-wallet` — settle (scopes: `wallet` + `insurance`)
7. Webhooks / `GET /orders/{id}` — when `status` is `completed`, `has_document` + `documents_url` appear (same JSON shape as eVisa); download via `GET /orders/{id}/documents`. While `processing`, document fields stay hidden.

## Payment model

- **Orders:** wallet only (`pay-wallet`). No per-order corporate card charge.
- **Top-up (manual):** card via `POST /wallet/topups` → open `checkout_url` (Stripe, 3DS). Balance updates after payment succeeds.
- **Auto top-up:** link a card once (`POST /wallet/auto-topup/setup` → Checkout setup → `POST /wallet/auto-topup/confirm`), then `PUT /wallet/auto-topup` with `enabled: true`, `target_balance_cents`, and `threshold_percent` (default **20**). After each successful `pay-wallet`, if balance &lt; `threshold_percent` of target, Stripe charges the saved card off-session and credits the wallet (refill to target, or fixed `amount_cents`). Cooldown 5 minutes between auto charges. Cards that require authentication may fail off-session — fall back to manual top-up.
- **Agency discount:** applies to **processing fee only**; government fee is full catalog amount.
- **Early cancel:** status must be `processing` (not sent to embassy) and payment age &lt; 1 hour → full amount credited back to wallet. After the window or after embassy submit: no Partner cancel.
- **Visa rejection:** typically non-refundable (see catalog `important_notes`).

## Endpoints (summary)

| Method | Path | Scope |
|--------|------|-------|
| GET | `/health` | — |
| GET | `/version` | — |
| GET | `/changelog` | — |
| GET | `/wallet` | wallet |
| GET | `/wallet/transactions` | wallet |
| GET | `/wallet/topup-packages` | wallet |
| POST | `/wallet/topups` | wallet |
| GET/PUT/DELETE | `/wallet/auto-topup` | wallet |
| POST | `/wallet/auto-topup/setup` | wallet |
| POST | `/wallet/auto-topup/confirm` | wallet |
| DELETE | `/wallet/auto-topup/card` | wallet |
| GET | `/reports/monthly` | wallet |
| GET | `/reports/financial` | wallet |
| POST | `/files` | files |
| GET | `/files` | files |
| GET | `/files/{id}` | files |
| DELETE | `/files/{id}` | files |
| GET | `/catalog/evisas` | evisa |
| GET | `/catalog/evisas/{id}` | evisa |
| POST | `/quotes/evisa` | evisa |
| POST | `/orders/evisa` | evisa |
| GET | `/catalog/insurance` | insurance |
| GET | `/catalog/insurance/{slug}` | insurance |
| POST | `/quotes/insurance` | insurance |
| POST | `/orders/insurance` | insurance |
| POST | `/orders/{id}/pay-wallet` | wallet + (evisa \| insurance matching `order_type`) |
| POST | `/orders/{id}/cancel` | wallet + (evisa \| insurance matching `order_type`) |
| GET | `/orders/{id}` | evisa \| insurance (matching `order_type`) |
| GET | `/orders/{id}/documents` | evisa \| insurance (matching `order_type`; insurance only when `completed`) |
| POST | `/orders/{id}/documents` | evisa |
| GET | `/orders` | evisa \| insurance |
| POST/GET/DELETE | `/webhooks` | webhooks |

### Order search

`GET /orders?status=processing&date_from=2026-10-01&date_to=2026-10-31&client_reference=YOUR-REF`

Filters apply to the Partner order index. Pass `client_reference` (or `reference`) on `POST /orders/evisa` or `POST /orders/insurance` so it is searchable later. Indexed rows include `order_type` (`evisa` or `insurance`).

### Reports

- `GET /reports/monthly?year=2026&month=10` — monthly statement (wallet by reason + orders)
- `GET /reports/financial?from=2026-10-01&to=2026-10-31` — same for an arbitrary range (max 366 days)

### Files

Uploads return metadata (`original_name`, `sha256`, `created_at`, …) and never a public URL.  
`GET /files`, `GET /files/{id}`, `DELETE /files/{id}` (remote delete + registry soft-delete).

## Rate limits (defaults)

| Window | Per key | Per agency |
|--------|---------|------------|
| Minute | 30 | 60 |
| Day | 1,000 | 2,000 |

Financial mutating routes (`pay-wallet`, `cancel`, `wallet/topups`, `wallet/auto-topup/*`) also share a tighter **per-agency** minute bucket (default 12/min). Catalog/quote keep the higher ceilings. Quotas are agency-scoped so one agency cannot exhaust another.

Headers: `X-RateLimit-*`, `Retry-After` on `429`.

Counters are file-backed on each app server (not a shared Redis store). On multi-node deploys each node enforces its own counters, so effective capacity scales with the number of nodes until a shared store is added.

## Errors

Every error is JSON with a stable `error_code`, human `message`, and optional machine-readable `details` (limits, missing fields, wallet shortfall, scopes, etc.). Also returned: `request_id` (and `X-Request-Id` header) for support, plus `docs_url`.

```json
{
  "ok": false,
  "error_code": "INSUFFICIENT_WALLET",
  "message": "Insufficient wallet balance.",
  "status": 402,
  "retry_after": null,
  "request_id": "prt_a1b2c3d4e5f60718",
  "method": "POST",
  "path": "orders/123/pay-wallet",
  "docs_url": "https://kawenter.com/docs/partner#errors",
  "details": {
    "balance_cents": 1200,
    "required_cents": 5000,
    "shortfall_cents": 3800,
    "currency": "USD",
    "hint": "Top up the agency wallet, then retry pay-wallet with the same Idempotency-Key.",
    "action": "topup_wallet"
  }
}
```

Rate limits (`429`) also include `limit`, `window`, `remaining`, `reset`, `limit_scope` (`key` | `agency`), and `Retry-After`.

## Related

- Public OpenAPI: https://kawenter.com/.well-known/openapi.json
- Public eVisa read API (no key): https://kawenter.com/api/evisa.php
- Public insurance read/quote (no key): https://kawenter.com/api/insurance.php
- Travel insurance apply (web): https://kawenter.com/travel-insurance
- Site context: https://kawenter.com/llms.txt
- Support: https://kawenter.com/contact
