# Companies, Child Companies, and Stores

Cheqi keeps four concepts separate:

- A **company** is the legal issuer named on a receipt.
- A **child company** is another legal issuer connected to a parent for
corporate structure and administration.
- A **store** is a location owned by exactly one company. It is not a legal
issuer by itself.
- An **integration** is the software calling Cheqi. It may receive explicit
grants from many issuer companies while keeping one integration credential.


The Core Rule
The authenticated integration says **who is calling**. The short-lived company
access token and active company grant say **which legal company it may act for**.
A parent-child relationship never grants receipt authority by itself.

## Choose the Right Model

| Real-world unit | Cheqi model | Why |
|  --- | --- | --- |
| Shop, restaurant, branch, webshop, or terminal under one legal entity | Store | It needs a location, not a separate legal identity |
| Subsidiary with its own registration or VAT identity | Child company | It is a separate legal receipt issuer |
| Franchisee operated by another legal entity | Child company | It needs independent consent, billing, reporting, and revocation |
| Brand or department under the same legal entity | Usually a store | An operational distinction does not create a legal issuer |
| Central POS or accounting platform | Integration | One caller can be explicitly authorized by many companies |


When unsure, ask: **Which legal name and tax registration must appear as the
seller?** Create or select that Cheqi company, then select one of its stores.

## A Real-World Group

```mermaid
flowchart TB
    Integration["Northstar central POS<br/>one integration credential"]
    Group["Northstar Group B.V.<br/>parent company"]
    NL["Northstar Retail NL B.V.<br/>child + legal issuer"]
    DE["Northstar Retail DE GmbH<br/>child + legal issuer"]
    Franchise["Independent Franchisee B.V.<br/>child + legal issuer"]

    Group -->|"corporate relationship only"| NL
    Group -->|"corporate relationship only"| DE
    Group -->|"franchise relationship only"| Franchise

    NL --> AMS["Amsterdam Store"]
    NL --> RTM["Rotterdam Store"]
    DE --> BER["Berlin Store"]
    Franchise --> UTR["Utrecht Store"]

    Integration -. "explicit NL grant" .-> NL
    Integration -. "explicit DE grant" .-> DE
    Integration -. "franchisee-approved grant" .-> Franchise
```

The integration credential does not multiply as companies are added. Each
legal issuer creates an explicit grant. At runtime, the integration exchanges
its credential for a short-lived token bound to the issuer it needs.

## Authentication and Authorization

Cheqi deliberately separates these:

| Object | Answers | Cardinality |
|  --- | --- | --- |
| Integration credential | Who is calling? | Usually one integration, with two active credentials during rotation |
| Company grant | Which issuer may it represent, with which scopes and stores? | One per integration/issuer pair |
| Company access token | Which grant is this short-lived request context using? | Requested through `/oauth2/token` when the integration needs to act for that issuer |


A company ID in a request is only a claim. Cheqi accepts it only when an active
grant exists for the authenticated integration.

```mermaid
sequenceDiagram
    participant POS as Central integration
    participant Token as Cheqi OAuth token endpoint
    participant Grant as Company grant
    participant API as Receipt API

    POS->>Token: client_credentials + grant_id + scope
    Token->>Grant: Validate active grant and requested scope subset
    Grant-->>Token: grant id + version + allowed stores
    Token-->>POS: Short-lived company access token
    POS->>API: Bearer token + storeId + encrypted receipt
    API->>Grant: Re-check status, version, scope, and store
    Grant-->>API: Authorized issuer context
    API-->>POS: Accepted
```

### Why the Parent Relationship Is Not Authority

The hierarchy exists for organization and administration. It does not prove
that a parent may legally issue receipts for a subsidiary or franchisee.
Changing a parent relationship therefore never changes receipt permissions.

- A verified organization administrator may approve grants for wholly owned
subsidiaries they administer.
- An independent franchisee approves its own grant and can suspend or revoke
it without affecting other franchisees.
- A third-party POS provider uses exactly the same grant mechanism even though
it has no corporate relationship with the merchant.


## One Integration for Thousands of Companies

One OAuth authorization may approve several companies. The one-time
authorization-code exchange returns Grant metadata for every approved company:

```json
{
  "grants": [
    {
      "issuer_company_id": "company-nl-uuid",
      "grant_id": "grant-uuid",
      "grant_version": 3,
      "company_legal_name": "Northstar Retail NL B.V.",
      "scopes": ["write_receipts", "read_stores"],
      "store_ids": ["store-amsterdam", "store-rotterdam"],
      "store_access_mode": "SELECTED_STORES"
    }
  ]
}
```

Use `POST /oauth2/authorization-code/exchange` for this one-time exchange.
It returns Grant metadata only; it does not issue an access token.

The integration stores its Grant-to-customer mapping. Before operating for a
company, it requests a short-lived company access token using the Grant ID:

```bash
curl -X POST https://api.cheqi.io/oauth2/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "client_credentials",
    "client_id": "your_client_id",
    "client_secret": "your_integration_secret",
    "grant_id": "grant-uuid",
    "scope": "write_receipts"
  }'
```

Cheqi returns a token that is:

- valid for about 15 minutes
- bound to one company grant and grant version
- limited to the requested subset of granted scopes
- invalidated when the grant changes, is suspended, or is revoked


When the token expires, request another through the same endpoint using the
same `grant_id`. No refresh token is needed.

To synchronize current Company and Store details after onboarding, call
`GET /oauth2/grants/{grantId}` with the Company-bound access token and the
`read_stores` scope.

One Credential Is Not Automatic Group Authority
The integration credential can request only issuers with an explicit active
grant. Guessing another company ID or adding a child relationship grants
nothing.

## Receipt Request Matrix

| Access token company | `storeId` | Result | Legal issuer |
|  --- | --- | --- | --- |
| Northstar Retail NL | Omitted | Allowed when the grant covers all stores | Northstar Retail NL |
| Northstar Retail NL | Amsterdam Store | Allowed | Northstar Retail NL |
| Northstar Retail NL | Berlin Store | Rejected; store belongs to another company | None |
| Northstar Group | Amsterdam Store | Rejected; hierarchy is not authority | None |
| Northstar Retail DE | Berlin Store | Allowed | Northstar Retail DE |
| Franchisee | Utrecht Store | Allowed only while its own grant is active | Franchisee |
| Selected-store grant | Omitted | Rejected for issuance | None |
| Any issuer | Inactive store | Rejected | None |


## Common Scenarios

### One Legal Company with Many Shops

Create one company and all shops as stores beneath it. One integration grant
can cover those stores because the legal issuer is the same.

### International Group

Create each national legal entity as a child company and its locations as
stores. Approve an explicit grant for each national company. The central
platform keeps one integration credential and exchanges it for the relevant
national issuer at checkout.

### Domino's-Style Franchise Network

Model brand-owned shops as stores of the brand's operating company. Model each
independent franchisee as its own company with its own stores.

Domino's central platform keeps one integration credential. Each franchisee
approves a company grant. The platform requests a short-lived access token for
the franchisee handling the sale. A franchisee can revoke only its own grant;
no company-specific secrets need to be distributed.

### Third-Party POS Provider

Each unrelated merchant explicitly grants the POS integration access. The POS
uses the same integration credential and exchange endpoint for every merchant.
Corporate hierarchy is not involved.

### Webshop and Physical Stores

If one legal company operates both, use one company. Omit `storeId` for online
sales when the grant covers all stores, or create a webshop store when an
explicit operational location is useful.

## Grant and Store Lifecycle

Issuer administrators can list, update, suspend, reactivate, and revoke grants.
Updates create a new immutable grant revision and revoke existing tokens for
that integration/company context.

A grant can cover:

- all direct stores of the issuer; or
- an explicit set of stores owned by the issuer.


Stores are deactivated rather than deleted so historical receipts retain their
location.

## Scopes

Available scope names are `write_receipts`, `read_receipts`, `write_stores`,
`read_stores`, `company_access`, and `account_access`.

## Issuance Checklist

1. Determine the exact legal seller from trusted transaction configuration.
2. Request a company access token through `/oauth2/token` with only the scopes needed.
3. If required, select an active store owned and allowed by that issuer.
4. Reuse the same access token context through recipient resolution and
encrypted submission.
5. On `401`, exchange again. On `403`, treat the grant, scope, company, or store
as unauthorized—do not silently fall back to another issuer.


## Related Guides

- [Authentication Overview](/authentication/overview)
- [API Key Authentication](/authentication/api-keys)
- [OAuth 2.0 Authentication](/authentication/oauth)
- [Sending Receipts](/receipts/sending)