{
  "openapi": "3.0.3",
  "info": {
    "title": "EIM ↔ SAP sandbox",
    "version": "0.1.0",
    "description": "Sandbox environment. All data here is test data and is not connected to any EIM or SAP system.\n\nFull guide: [/](/) · Machine-readable spec: [/openapi.json](/openapi.json)\n\nThrowaway test API for proving connectivity between SAP Integration Suite (CPI) and Energy In Motion. **Not production.** Payloads are stored as received and field names are not validated.\n\n**How to try it here**\n1. Click **Authorize**.\n2. Under **clientCredentials (OAuth2)** enter the client id and secret EIM sent you, and click Authorize. Swagger fetches a token from `/oauth/token` for you.\n   Alternatively call `POST /oauth/token` below yourself and paste the `access_token` under **bearerToken**.\n3. Open any call, click **Try it out**, then **Execute**.\n\nEvery request is logged on EIM's side, including refused ones, so we can see exactly what arrived.\n\n**Token:** `POST /oauth/token` with HTTP Basic `client_id:client_secret` (or `client_id` / `client_secret` in a form or JSON body). Returns a bearer token valid 30 days for this sandbox. Production will use short-lived tokens from EIM's identity provider."
  },
  "servers": [
    {
      "url": "/",
      "description": "This sandbox"
    }
  ],
  "tags": [
    {
      "name": "Auth",
      "description": "Get a bearer token."
    },
    {
      "name": "SAP to EIM",
      "description": "Calls SAP CPI makes to EIM."
    },
    {
      "name": "EIM answers SAP",
      "description": "Data SAP pulls from EIM."
    },
    {
      "name": "Check",
      "description": "See what EIM received."
    }
  ],
  "paths": {
    "/api/v1/health": {
      "get": {
        "tags": [
          "Check"
        ],
        "summary": "Service is up",
        "security": [],
        "responses": {
          "200": {
            "description": "Up",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "service": "sap-test",
                  "now": "2026-09-29T05:00:00.000Z"
                }
              }
            }
          }
        }
      }
    },
    "/oauth/token": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Get a bearer token",
        "description": "Send the client id and secret as HTTP Basic. A form body (`grant_type=client_credentials&client_id=…&client_secret=…`) or a JSON body with `client_id` and `client_secret` also works.",
        "security": [
          {
            "clientBasic": []
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "properties": {
                  "grant_type": {
                    "type": "string",
                    "example": "client_credentials"
                  },
                  "client_id": {
                    "type": "string"
                  },
                  "client_secret": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token issued",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Token"
                },
                "example": {
                  "access_token": "QZNl5f…",
                  "token_type": "Bearer",
                  "expires_in": 2592000,
                  "expires_at": "2026-10-29T05:00:00.000Z"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/InvalidClient"
          }
        }
      }
    },
    "/api/v1/sap/equipment": {
      "post": {
        "tags": [
          "SAP to EIM"
        ],
        "summary": "Create equipment (vehicle or battery)",
        "description": "Sent by SAP when a new vehicle or battery is invoiced (equipment category S). Stored exactly as received. Only the equipment number (`equipmentNumber`, `EQUNR` or `equipment_number`) and VIN (`vin` or `VIN`) are read, to echo back. Send your real S/4 field names: they are what we will map.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Equipment"
              },
              "examples": {
                "vehicle": {
                  "summary": "Vehicle",
                  "value": {
                    "equipmentNumber": "10000123",
                    "equipmentCategory": "S",
                    "equipmentType": "VEHICLE",
                    "vin": "MAT000000TEST0001",
                    "macAddress1": "AA:BB:CC:DD:EE:01",
                    "macAddress2": "AA:BB:CC:DD:EE:02",
                    "imei": "356789012345678",
                    "rfid": "RFID-TEST-0001",
                    "customerNumber": "0000100001",
                    "customerName": "Test Customer Pvt Ltd",
                    "salesMethod": "BAAS",
                    "invoiceDate": "2026-09-28",
                    "licencePlate": null
                  }
                },
                "battery": {
                  "summary": "Battery",
                  "value": {
                    "equipmentNumber": "10000456",
                    "equipmentCategory": "S",
                    "equipmentType": "BATTERY",
                    "batterySerial": "EIMB350TEST000000000001",
                    "capacityKwh": 350,
                    "customerNumber": "0000100001",
                    "salesMethod": "BAAS",
                    "invoiceDate": "2026-09-28"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Received and stored",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EquipmentAck"
                },
                "example": {
                  "status": "received",
                  "eimId": "447d60ae-cd00-4a6d-a515-5083632f0de6",
                  "receivedAt": "2026-09-29T05:02:11.410Z",
                  "echo": {
                    "equipmentNumber": "10000123",
                    "vin": "MAT000000TEST0001"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidJson"
          },
          "401": {
            "$ref": "#/components/responses/InvalidToken"
          }
        }
      },
      "get": {
        "tags": [
          "Check"
        ],
        "summary": "List equipment EIM received",
        "description": "The last 100 equipment records, newest first.",
        "responses": {
          "200": {
            "description": "Stored records",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/StoredEquipment"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/InvalidToken"
          }
        }
      }
    },
    "/api/v1/sap/inbox": {
      "post": {
        "tags": [
          "SAP to EIM"
        ],
        "summary": "Send any other payload",
        "description": "For interfaces that have no endpoint yet: customer master, contract id, licence plate update, payment against an invoice. Any JSON is stored and echoed back.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              },
              "examples": {
                "customer": {
                  "summary": "Customer master",
                  "value": {
                    "type": "CUSTOMER_MASTER",
                    "customerNumber": "0000100001",
                    "name": "Test Customer Pvt Ltd",
                    "gstin": "27AAAAA0000A1Z5",
                    "address": {
                      "city": "Pune",
                      "state": "MH",
                      "pin": "411001"
                    }
                  }
                },
                "plate": {
                  "summary": "RTO licence plate update",
                  "value": {
                    "type": "RTO_UPDATE",
                    "equipmentNumber": "10000123",
                    "licencePlate": "MH12AB1234"
                  }
                },
                "payment": {
                  "summary": "Payment against a charging invoice",
                  "value": {
                    "type": "PAYMENT",
                    "invoiceNumber": "EIM-TEST-1790537815273",
                    "amount": 47375.82,
                    "currency": "INR",
                    "paidAt": "2026-09-29T10:00:00+05:30"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Received, echoed",
            "content": {
              "application/json": {
                "example": {
                  "status": "received",
                  "id": "1a0f7741-2f36-4eb8-82b5-cb27a3315cac",
                  "receivedAt": "2026-09-29T05:03:00.000Z",
                  "echo": {
                    "type": "RTO_UPDATE"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidJson"
          },
          "401": {
            "$ref": "#/components/responses/InvalidToken"
          }
        }
      },
      "get": {
        "tags": [
          "Check"
        ],
        "summary": "List inbox items EIM received",
        "responses": {
          "200": {
            "description": "Stored items, newest first"
          },
          "401": {
            "$ref": "#/components/responses/InvalidToken"
          }
        }
      }
    },
    "/api/v1/sap/odometer": {
      "get": {
        "tags": [
          "EIM answers SAP"
        ],
        "summary": "Odometer for a vehicle",
        "description": "Pulled by S/4 when a service notification is raised. The sandbox answers a fixed dummy reading; the shape is what matters.",
        "parameters": [
          {
            "name": "vin",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "MAT000000TEST0001"
          }
        ],
        "responses": {
          "200": {
            "description": "Reading",
            "content": {
              "application/json": {
                "example": {
                  "vin": "MAT000000TEST0001",
                  "odometerKm": 48213.6,
                  "readAt": "2026-09-29T05:04:00.000Z",
                  "source": "sap-test dummy"
                }
              }
            }
          },
          "400": {
            "description": "vin missing",
            "content": {
              "application/json": {
                "example": {
                  "error": "missing_vin",
                  "error_description": "Query parameter vin is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/InvalidToken"
          }
        }
      }
    }
  },
  "security": [
    {
      "clientCredentials": []
    },
    {
      "bearerToken": []
    }
  ],
  "components": {
    "securitySchemes": {
      "clientCredentials": {
        "type": "oauth2",
        "description": "Enter the client id and secret; Swagger fetches the token for you.",
        "flows": {
          "clientCredentials": {
            "tokenUrl": "/oauth/token",
            "scopes": {}
          }
        }
      },
      "bearerToken": {
        "type": "http",
        "scheme": "bearer",
        "description": "Paste an access_token from POST /oauth/token."
      },
      "clientBasic": {
        "type": "http",
        "scheme": "basic",
        "description": "Client id as username, client secret as password."
      }
    },
    "schemas": {
      "Token": {
        "type": "object",
        "properties": {
          "access_token": {
            "type": "string"
          },
          "token_type": {
            "type": "string",
            "example": "Bearer"
          },
          "expires_in": {
            "type": "integer",
            "description": "Seconds",
            "example": 2592000
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Equipment": {
        "type": "object",
        "description": "Our guess at the shape, from the integration sheet. Any extra fields are kept.",
        "additionalProperties": true,
        "properties": {
          "equipmentNumber": {
            "type": "string"
          },
          "equipmentCategory": {
            "type": "string",
            "example": "S"
          },
          "equipmentType": {
            "type": "string",
            "enum": [
              "VEHICLE",
              "BATTERY"
            ]
          },
          "vin": {
            "type": "string"
          },
          "macAddress1": {
            "type": "string"
          },
          "macAddress2": {
            "type": "string"
          },
          "imei": {
            "type": "string"
          },
          "rfid": {
            "type": "string",
            "description": "EIM charging network RFID"
          },
          "batterySerial": {
            "type": "string"
          },
          "customerNumber": {
            "type": "string"
          },
          "customerName": {
            "type": "string"
          },
          "salesMethod": {
            "type": "string",
            "description": "BAAS (sold without battery) or WITH_BATTERY"
          },
          "invoiceDate": {
            "type": "string",
            "format": "date"
          },
          "licencePlate": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "EquipmentAck": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "example": "received"
          },
          "eimId": {
            "type": "string",
            "format": "uuid"
          },
          "receivedAt": {
            "type": "string",
            "format": "date-time"
          },
          "echo": {
            "type": "object",
            "properties": {
              "equipmentNumber": {
                "type": "string",
                "nullable": true
              },
              "vin": {
                "type": "string",
                "nullable": true
              }
            }
          }
        }
      },
      "StoredEquipment": {
        "type": "object",
        "properties": {
          "eimId": {
            "type": "string"
          },
          "receivedAt": {
            "type": "string",
            "format": "date-time"
          },
          "from": {
            "type": "string",
            "example": "sap-cpi"
          },
          "payload": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "error_description": {
            "type": "string"
          }
        }
      }
    },
    "responses": {
      "InvalidClient": {
        "description": "Wrong client id or secret",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "invalid_client",
              "error_description": "Bad client id or secret"
            }
          }
        }
      },
      "InvalidToken": {
        "description": "Bearer token missing, unknown or expired",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "invalid_token",
              "error_description": "Missing, unknown or expired bearer token"
            }
          }
        }
      },
      "InvalidJson": {
        "description": "Body is not valid JSON",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "invalid_json",
              "error_description": "Unexpected token t in JSON at position 2"
            }
          }
        }
      }
    }
  }
}
