# Partner Integration API

API specification for freight forwarding system (FFS) partners integrating with BravoTran.

## Overview

BravoTran uses an event-driven pull model to stay in sync with your freight forwarding system:

1. Your system sends an **event notification** to BravoTran when an entity is created or updated.
2. BravoTran reads the entity type and identifier from the event.
3. BravoTran issues a `GET` request to your API with the entity type and identifier.
4. Your API returns the entity as JSON per this specification.

BravoTran also **POSTs approved invoices** to your system for cost posting. When an invoice is approved in BravoTran, it sends a `POST /payables-invoices` request to your API with the invoice details. Your system must create or record the invoice accordingly.

![API Flow Diagram](images/api-flow.png)

### Polling alternative

If your system cannot reliably push live event notifications, you may instead implement the optional list endpoints `GET /orgs`, `GET /jobs`, and `GET /payables-invoices`. BravoTran will periodically poll them with an `updated_after` window, get back the identifiers of anything that changed, then call the existing single-entity detail endpoints to fetch each one. Implement **either** the events API **or** the list endpoints — not both. All three list endpoints must be implemented together so that newly created payables invoices are also surfaced.

Creates and updates are surfaced through the same filter: when an entity is created, set `updated_at` to the creation timestamp and it will appear in any subsequent polling response whose `updated_after` is at or before that timestamp. There is no separate "creation" feed.

## Terminology

| Term | Definition |
|------|-----------|
| **FFS** | Freight Forwarding System — your system |
| **Company** | A country-level entity in the FFS; maps to a BravoTran **Account** |
| **Account** | BravoTran's representation of a company/country |
| **Org** | Vendors, carriers, creditors, debtors |
| **Job** | A consol (consolidation/master) or shipment (house) |
| **Accrual** | Expected charges on a job |
| **Charge Line** | Line items on a payables invoice |
| **Payables Invoice** | AP invoice from a creditor |
| **Outbound Payables Invoice** | Approved invoice posted from BravoTran to the partner's system for cost posting |

BravoTran maps a **Company** in the FFS to an **Account** in BravoTran. Often a company represents a country. It is acceptable to have more than one account for a country if that country has multiple companies, but a single account must never represent multiple companies or countries.

## Conventions

- **`external_id`** — Unique, immutable identifier for every entity. Used as the foreign key between systems. Typically the primary key in your database. Not visible to end users.
- **`updated_at`** — [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) timestamp of when the entity was last modified. BravoTran uses this as a version marker to prevent overwriting with stale data. For jobs, this must update when any child data changes (e.g., accrual added/edited, shipment added to consol). On creation, `updated_at` must be set to (at least) the creation timestamp so newly created entities appear in polling responses alongside updates — the polling endpoints make no distinction between creates and updates.
- **Amounts** — Wherever there is an amount, a corresponding `currency` ([ISO 4217](https://en.wikipedia.org/wiki/ISO_4217)) must be provided.
- **Country codes** — Country fields use [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) two-letter codes.
- **Nested references** — Related entities are represented as nested objects containing at minimum an `external_id`.

## Staff

Staff data will be provided via flat file. Documentation forthcoming.

## Charge Codes

Charge code data will be provided via flat file. Documentation forthcoming. Accruals and charge lines reference charge codes by `external_id`; the mapping is maintained through the flat file data.

## Tax Codes

Tax code data will be provided via flat file. Documentation forthcoming.

## Authentication

Both directions of communication support one of the following authentication methods, agreed upon during onboarding:

- **OAuth 2.0** — Client credentials flow
- **HTTP Basic Auth** — Username and password
- **Bearer Token** — Static token in the `Authorization` header


Version: 1.0.0

## Servers

Partner-hosted API — where BravoTran fetches entity data
```
https://api.yourserver.com
```

## Security

### OAuth2.0-Partner

BravoTran → Partner: OAuth 2.0 client credentials flow.

Type: oauth2

### HTTP-Basic-Partner

BravoTran → Partner: HTTP Basic authentication.

Type: http
Scheme: basic

### Bearer-Token-Partner

BravoTran → Partner: Bearer token in the Authorization header.

Type: http
Scheme: bearer

### OAuth2.0-BravoTran

Partner → BravoTran: OAuth 2.0 client credentials flow.

Type: oauth2

### HTTP-Basic-BravoTran

Partner → BravoTran: HTTP Basic authentication.

Type: http
Scheme: basic

### Bearer-Token-BravoTran

Partner → BravoTran: Bearer token in the Authorization header.

Type: http
Scheme: bearer

## Download OpenAPI description

[Partner Integration API](https://apidocs.bravotran.com/_bundle/openapi.yaml)

## Events

Event notifications sent from the FFS to BravoTran.

### Send event notification to BravoTran

 - [POST /events](https://apidocs.bravotran.com/openapi/events/sendevent.md): This endpoint is hosted by BravoTran, not the partner. Required unless you implement the polling alternative (GET /orgs, GET /jobs, GET /payables-invoices). Implement either this events API or the list endpoints — not both.

Your system calls this endpoint to notify BravoTran that an entity has been created or updated.
BravoTran will then fetch the entity details from your API.

## Orgs

### List updated organizations

 - [GET /orgs](https://apidocs.bravotran.com/openapi/orgs/listorgs.md): Returns a list of org identifiers, optionally filtered to those updated within a time window.

Optional. Provided as an alternative to POST /events for partners that cannot push live event notifications. Implement either the events API or these list endpoints — not both.

Response items contain only external_id. To fetch full org details, call GET /orgs/{external_id} for each entry.

### Get an organization

 - [GET /orgs/{external_id}](https://apidocs.bravotran.com/openapi/orgs/getorg.md): Returns a single org by their external ID. Implementation is required.

> Tax note: Tax-related fields (e.g., tax on amounts, tax code references) are marked as required but are optional for non-tax / US-based accounts. BravoTran determines the tax mode based on the authenticated account.

If multiple source tables are combined into the orgs entity, prefix the external_id with the source type to maintain uniqueness (e.g., vendor-123).

## Jobs

### List updated jobs

 - [GET /jobs](https://apidocs.bravotran.com/openapi/jobs/listjobs.md): Returns a list of job identifiers, optionally filtered to those updated within a time window.

Optional. Provided as an alternative to POST /events for partners that cannot push live event notifications. Implement either the events API or these list endpoints — not both.

A job's updated_at reflects changes to nested data as well (accruals, child shipments linked, etc.), so this endpoint surfaces any change that should trigger a re-sync. Response items contain only external_id. To fetch full job details, call GET /jobs/{external_id} for each entry.

### Get a job

 - [GET /jobs/{external_id}](https://apidocs.bravotran.com/openapi/jobs/getjob.md): Returns a single job by its external ID. Implementation is required.

> Tax note: Tax-related fields (e.g., tax on amounts, tax code references) are marked as required but are optional for non-tax / US-based accounts. BravoTran determines the tax mode based on the authenticated account.

Jobs contain nested accruals, container numbers, way bills, and additional references.
When a job is updated (including changes to accruals, child shipments added to a consol, etc.),
the updated_at timestamp must reflect the most recent change.

## Payables Invoices

### List updated payables invoices

 - [GET /payables-invoices](https://apidocs.bravotran.com/openapi/payables-invoices/listpayablesinvoices.md): Returns a list of payables invoice identifiers, optionally filtered to those updated within a time window.

Optional. Provided as an alternative to POST /events for partners that cannot push live event notifications. Implement either the events API or these list endpoints — not both.

Response items contain only external_id. To fetch full invoice details, call GET /payables-invoices/{external_id} for each entry.

### Get a payables invoice

 - [GET /payables-invoices/{external_id}](https://apidocs.bravotran.com/openapi/payables-invoices/getpayablesinvoice.md): Returns a single payables invoice by its external ID. Implementation is required.

> Tax note: Tax-related fields (e.g., tax on amounts, tax code references) are marked as required but are optional for non-tax / US-based accounts. BravoTran determines the tax mode based on the authenticated account.

Payables invoices contain nested charge lines, each referencing a job and optionally an accrual.

## Outbound Payables Invoices

Approved invoices that BravoTran posts to the partner's system for cost posting.

### Receive an approved payables invoice from BravoTran

 - [POST /payables-invoices](https://apidocs.bravotran.com/openapi/outbound-payables-invoices/postpayablesinvoice.md): This endpoint is hosted by the partner, not BravoTran. Implementation is required.

BravoTran calls this endpoint when an invoice has been approved and is ready for cost posting.
Your system must create or record the invoice accordingly.

> Tax note: Tax-related fields (tax on amounts, tax_code, tax_rate) are only present for tax-enabled accounts. For non-tax / US-based accounts these fields will be absent or null. BravoTran determines the tax mode based on the authenticated account.

