# ERPLab

> ERPLab hosts high-fidelity, tenant-isolated ERP simulators (Oracle Fusion Cloud ERP and more) with the same REST, SOAP and OAuth 2.0 integration surface as the real vendors, so integration code can be built and validated end-to-end without a production ERP.

Each simulator is served under a tenant-specific base URL of the form `https://erplab.cloud/sim/{environmentKey}`. Sign in at https://erplab.cloud/auth to obtain an `environmentKey` and OAuth 2.0 client credentials for your tenant. Public documentation and OpenAPI specifications below describe the exact endpoints, payload shapes, query grammar, error envelopes and workflows every simulator exposes; they are the authoritative contract.

## Authentication

All REST and SOAP calls require an OAuth 2.0 bearer token. Only the client-credentials grant is supported, and `scope` is REQUIRED on the token request — Oracle marks it required, and a request without it is refused with `400 invalid_request`.

```http
POST https://erplab.cloud/sim/{environmentKey}/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&scope=urn:opc:resource:consumer::all&client_id={client_id}&client_secret={client_secret}
```

Credentials may instead be sent as `Authorization: Basic base64(client_id:client_secret)`; `grant_type` and `scope` stay in the form body either way.

```json
{ "access_token": "…", "token_type": "Bearer", "expires_in": 3600, "scope": "urn:opc:resource:consumer::all" }
```

Send `Authorization: Bearer {access_token}` on every subsequent call. Tokens are valid for 3600 seconds; cache one and re-mint shortly before it expires rather than minting per request.

Request `urn:opc:resource:consumer::all` on its own — combining it with another scope is refused with `400 invalid_scope`, as is any scope beyond the one granted to the client. A `401 invalid_client` means an unknown client, a wrong secret, a revoked client, or a credential used against a different environment key; all four are reported identically and cannot be told apart.

## Reading the contract

The OpenAPI document is authoritative **per operation**. A child collection implements fewer query parameters than its parent, so read the parameter list on the operation you are about to call rather than assuming the parent's — a parameter the operation does not declare is refused with `400 REST-01003` naming it, never accepted and ignored. Child collections and actions have their own schemas, not the parent resource's.

Not every attribute can be filtered. Each one in the OpenAPI schema carries `x-queryable` — whether **this API** accepts a `q` filter on it — and `x-queryable-oracle` — `true`, `false` or `unverified` for what is known about Oracle's own flag. Read them rather than guessing; a filter on an attribute marked false is refused with `400 REST-01003`, never silently ignored.

`x-queryable-oracle` is what makes a refusal actionable, and the two values point opposite ways. `false` means Oracle refuses the filter too — a dead end, do not write it. `true` means Oracle allows it and this simulator has not implemented it, so the filter is right and would work in production; expect a 400 here and do not remove it from your code. `unverified` means Oracle's flag was never confirmed and is not being guessed at.

Where Oracle's flag is known (`true` or `false`), this API is **never broader** than Oracle — a filter accepted here is one a real pod accepts — and that is enforced mechanically rather than by intention. It may be narrower. Where the flag is `unverified`, neither direction is established.

Every error body carries `o:errorCode`. That is the field to branch on; `title` and `detail` are prose and may be reworded. The envelope is `{ title, status, type, o:errorCode, detail, o:errorDetails? }`.

To confirm that a payment landed, read `standardReceiptApplications` under `receivablesCustomerAccountActivities` — creating a receipt never applies it, and the invoice balance changes only once a separate asynchronous process has applied the cash.

## Docs

- [Oracle Fusion Cloud ERP — integration documentation (Markdown)](https://erplab.cloud/api/public/oracle-fusion/docs.md): Full reference as plain text — authentication, every REST resource with its attributes and query parameters, SOAP services, the capability matrix with support status, the error reference, and the end-to-end integration guide. Fetch this one; it needs no JavaScript.
- [Oracle Fusion Cloud ERP — OpenAPI 3.1 specification](https://erplab.cloud/api/public/oracle-fusion/openapi.json): Machine-readable API contract. Use this to discover endpoints, request/response schemas, path/query parameters and security schemes. Authoritative per operation.
- [Oracle Fusion Cloud ERP — integration documentation (browser)](https://erplab.cloud/public/oracle-fusion): The same content as a web page. Client-rendered, so it requires JavaScript — use the Markdown link above for programmatic access.

## Task guides

- [Oracle Fusion — External Provider Integration Guide](https://erplab.cloud/api/public/oracle-fusion/docs.md#external-provider-integration-guide): End-to-end walkthrough — connect, authenticate, list/read/write each supported resource, filter with the `q` grammar, run incremental sync with `LastUpdateDate`, split installments, and recover from errors.
- [Oracle Fusion — Capability matrix](https://erplab.cloud/api/public/oracle-fusion/docs.md#capability-matrix): Every capability with its support status. This is where to check whether something is unsupported before building against it.
- [Oracle Fusion — Error reference](https://erplab.cloud/api/public/oracle-fusion/docs.md#errors): Error envelope shape, status codes, error codes and recovery actions.

## Optional

- [ERPLab public index](https://erplab.cloud/public): List of all published ERP simulators and their documentation.
- [Sign in](https://erplab.cloud/auth): Obtain a tenant environment key and OAuth 2.0 client credentials.
