Partner API
The Partner API is the third BFF surface alongside operator and passenger. It targets B2B integrators — airline systems, corporate travel desks, OTAs, ground-handling agents, regulators — who need to call Nexa programmatically.
Base URL: https://na.api.nexastudio.io/partner/v1 (or your regional equivalent).
Audience: https://internal.nexa/v1.
Auth: OAuth2 client credentials per registered partner. See Authentication.
What you can do via the Partner API
| Capability | Use case |
|---|---|
| Read case state | Airline ops dashboard pulling Nexa-resolved disruptions; corporate travel desk monitoring VIP itineraries. |
| Subscribe to disruption events | Downstream automation — e.g., the airline's CRM ingesting passenger compensation events. |
| Push disruption events in | The airline's PSS / DCS notifying Nexa of a confirmed disruption. |
| Bounded write operations | Forced re-evaluation of a VIP passenger's case; partner-initiated passenger notification. Each write scope is bounded per partner. |
What you cannot do
- The Partner API does not expose operator workflows (manual review, override, audit export). Those are operator-only via the operator console.
- It does not surface the passenger PWA's snapshot. Passengers always reach Nexa through the per-tenant passenger subdomain.
- It does not call internal vendor adapters (Amadeus, Hotelbeds, Pomelo) on a partner's behalf — those are platform-internal and tenant-scoped.
Onboarding
Partner registration is a 3-step process driven by Nexa Customer Success:
- Identify the airline. A partner is registered per airline at a time. A multi-tenant integrator (e.g., a corporate travel platform serving LATAM and Avianca) holds two registrations.
- Pick the scopes. From the catalog below, pick the minimum scopes the integration needs.
- Receive credentials. Nexa provisions an OAuth2 M2M client and delivers
client_id+client_secretvia secret-sharing channel. Secrets rotate every 90 days; a 14-day dual-key window covers the rotation.
Authentication
OAuth2 client credentials. Token request:
POST https://nexa.auth0.com/oauth/token HTTP/1.1
Content-Type: application/json
{
"grant_type": "client_credentials",
"client_id": "<your-client-id>",
"client_secret": "<your-client-secret>",
"audience": "https://internal.nexa/v1"
}
Token TTL: 1 hour. Cache the token client-side until exp - 60s. On a 401 from Nexa, force-refresh once before propagating.
Scopes
| Scope | Grants |
|---|---|
cases.read | GET /v1/cases/* — read case state and manifests |
cases.events.subscribe | Webhook subscription for case lifecycle events |
bookings.read | GET /v1/bookings/* — read reservations |
vouchers.read | GET /v1/vouchers/* — read voucher contents (no PII beyond what the passenger received) |
disruptions.events.subscribe | Webhook subscription for disruption.detected, case.opened |
disruptions.events.publish | POST /v1/disruptions — push a confirmed disruption to Nexa |
policies.read | GET /v1/policies — read active policies (for partner-side validation) |
metrics.read | GET /v1/metrics?kpi=… — gated to the certified KPI catalog |
passenger.notify | POST /v1/passengers/{urn}/notify — bounded partner-initiated message |
cases.priority.request | POST /v1/cases/{urn}/priority-request — bounded request to elevate priority |
Every endpoint declares its required scope; unauthorized requests fail with 403 Forbidden.
REST endpoints
Read
| Method | Path | Scope |
|---|---|---|
GET | /partner/v1/cases/{case_urn} | cases.read |
GET | /partner/v1/cases?airport=…&from=…&to=…&cursor=… | cases.read |
GET | /partner/v1/cases/{case_urn}/passengers | cases.read |
GET | /partner/v1/cases/{case_urn}/services | cases.read |
GET | /partner/v1/disruptions?since=…&cursor=… | disruptions.events.subscribe |
GET | /partner/v1/bookings/{booking_urn} | bookings.read |
GET | /partner/v1/vouchers/{voucher_urn} | vouchers.read |
GET | /partner/v1/passengers/{passenger_urn}/cases | cases.read |
GET | /partner/v1/passengers/{passenger_urn}/vouchers | vouchers.read |
GET | /partner/v1/policies | policies.read |
GET | /partner/v1/metrics?kpi=…&from=…&to=… | metrics.read |
Bounded write
| Method | Path | Scope | Notes |
|---|---|---|---|
POST | /partner/v1/disruptions | disruptions.events.publish | Push a confirmed disruption — manifest, next-flight, tier mix. Idempotent on externalEventId. |
POST | /partner/v1/cases/{case_urn}/priority-request | cases.priority.request | Request elevated priority (e.g., VIP routing). Bounded — rate-limited per partner. |
POST | /partner/v1/passengers/{passenger_urn}/notify | passenger.notify | Partner-initiated message to a passenger via Nexa's notification surface (templated; partner cannot inject free-form text). |
Push a disruption (the most common partner write)
POST /partner/v1/disruptions HTTP/1.1
Authorization: Bearer <token>
Content-Type: application/json
{
"externalEventId": "LA500-20260513-CANCELLED",
"airlineUrn": "urn:airline:latam",
"flight": {
"iataDesignator": "LA500",
"originAirport": "SCL",
"destinationAirport": "GRU",
"scheduledDeparture": "2026-05-13T18:00:00Z"
},
"disruption": {
"type": "CANCELLED",
"reason": "WEATHER",
"decidedAt": "2026-05-13T15:42:00Z"
},
"passengers": [
{
"pnr": "XYZ123",
"lastName": "PEREZ",
"cabinClass": "ECONOMY",
"loyaltyTier": "STANDARD",
"contact": { "email": "...", "phone": "+56...", "language": "es" }
}
// …
],
"nextFlight": {
"iataDesignator": "LA502",
"scheduledDeparture": "2026-05-14T08:00:00Z"
}
}
Response (202 Accepted):
{
"caseUrn": "urn:case:c-7f8e1",
"status": "OPEN",
"subCaseCount": 184,
"correlationUrn": "urn:correlation:..."
}
The endpoint is idempotent on externalEventId — replays return the same caseUrn. Updates to the manifest (added passengers, corrected next-flight) are handled by a separate PATCH /partner/v1/cases/{case_urn}/manifest endpoint.
Webhook-out (event subscriptions)
For partners with *.events.subscribe scopes, Nexa pushes events to a partner-registered webhook URL. Each event POST is signed with HMAC-SHA256:
POST https://your-system.example/nexa-webhook HTTP/1.1
Content-Type: application/json
X-Nexa-Signature: sha256=<hmac>
X-Nexa-Event-Type: case.resolved
X-Nexa-Event-Urn: urn:event:...
X-Nexa-Tenant: urn:airline:latam
{
"type": "case.resolved",
"occurred_at": "2026-05-13T20:11:00Z",
"case_urn": "urn:case:c-7f8e1",
"data": { ... }
}
Properties:
- HMAC-SHA256 with a per-partner secret (separate from the OAuth client secret).
- Idempotency key:
X-Nexa-Event-Urn(also in the body) — partners must dedupe. - Retries: exponential backoff up to 24 h. After 24 h of failures, the subscription is paused and the partner contact is notified.
- Replay:
GET /partner/v1/events/replay?since=<urn>re-delivers events from the last 7 days.
See Webhooks for the full event-type catalog and signature verification.
Rate limits & quotas
| Tier | Read RPM | Write RPM | Webhook delivery |
|---|---|---|---|
| Tier-1 (strategic partner) | 1200 | 240 | p95 < 5 s |
| Tier-2 (standard) | 600 | 120 | p95 < 30 s |
| Tier-3 (best-effort) | 60 | 10 | best-effort |
Quotas are enforced by the same egress token-bucket primitive that throttles outbound vendor calls. Soft limit emits 429 with Retry-After; hard limit additionally alerts the partner contact.
SLA
| Tier | Read availability | Write availability |
|---|---|---|
| Tier-1 | 99.95% | 99.9% |
| Tier-2 | 99.9% | 99.5% |
| Tier-3 | 99% | n/a |
Availability is measured monthly. Maintenance windows are excluded; failed dependencies (vendor-side outages) are excluded. See Operations & SLA.
Tenant isolation
A partner token is tenant-scoped. A request authenticated for urn:airline:latam cannot read a case owned by another airline; the request returns 403. Multi-tenant partners hold one registration per airline.
The enforcement is layered:
- Token claim —
https://nexa/tenant_urnin the JWT. - Application-level guard — every query is automatically filtered by
tenant_urn. - Database — analytical reads use row-level security.
Cross-tenant reads are not allowed via the partner API even for "platform-wide" partners (e.g., a regulator). Each regulator gets a tenant-specific registration per airline they oversee.
Versioning
URL-prefix versioning: /partner/v1/*. Breaking changes mint /partner/v2/*. Deprecation notice is 6 months with Deprecation and Sunset HTTP headers on every response from the deprecated version. Removal is at 12 months.
Audit
Every partner read and write is recorded in the audit log against urn:partner:<id>, including correlation URN, payload hash, and the airline's tenant URN. Partners can request their audit log via Nexa Customer Success.
Where to next
- Authentication
- Webhooks — event types and signature verification.
- Operator API — for context on what operators can do.
- OpenAPI — live spec for SDK generation.