Getting Started with Plug and Charge
Shell Plug and Charge API's are based on the "Open Plug&Charge Protocol" (OPCP) to support implementing ISO-15118-2. The intended audience for these API's are OEMs, CPOs and MSPs.
/v1/events is providing a simpler, cheaper and more safe alternative API instead of the WebHook API.
This API product consists of the following end points:
API End Point | API Functionality |
---|---|
GET /v1/events | Get events about created or revoked contracts. |
GET /v1/oem/provCerts/lookupVehicle/{pcid} | Check if a contract can be created for a certain PCID. |
PUT /v1/cps/generate/signedContractData | Generate or update the contract. |
POST /v1/ccp/signedContractData | Return an ISO-15118-2 CertificateInstallationRes based on the provided CertificateInstallationReq. |
DELETE /v1/ccp/signedContractData/{emaid} | Delete and revoke the contract for the provided EMAID. |
Authentication
Shell API’s are secured by OAuth 2.0. It uses the 'Client Credentials' Grant Type to allow the API consumer to access data. The end to end process is illustrated in the sequence diagram below.
Requesting credentials (manual)
The partner requests a client id
and client secret
for use with their application. Shell's contact will provide these
credentials to the partner.
The partner configures the application to use OAuth2. It will use the 'Client Credentials' Grant Type.
On the Shell side we also need to configure a role with claims for that client id.
Requesting a JWT token (app)
Paramaters
Once you receive the client ID & Secret, next step is to call the https://api-test.shell.com/v2/oauth/token endpoint to authenticate. Following are the key parameters-
Name | Value |
---|---|
Method | POST |
Authorization Type | OAuth 2.0 |
Auth URI | https://api-test.shell.com/v2/oauth/token |
Client_Id | **** (OAuth Client ID) |
Client Secret | **** (OAuth Client Secret) |
Grant Type | client_credentials |
Example
curl --location --request POST ' https://api-test.shell.com/v2/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=***********' \
--data-urlencode 'client_secret=*************' \
--data-urlencode 'grant_type=client_credentials'
Response
{
"access_token": "***********",
"token_type": "Bearer",
"expires_in": 899
}
The response will contain the following parameters:
- access_token: The token to be used to call the functional APIs
- expires_in: The amount of seconds until the access token expires.
- token_type: Bearer
Exception Handling
All error scenarios are returned with a response body and identifier.
{
"Error": "401",
"message": "Authorization value is incorrect to process the request."
}
HTTP Code | Description |
---|---|
400 Bad Request | If Invalid scope passed to Token url |
Invalid grant type passed to Token url | |
401 Unauthorized | If Invalid id/secret passed to Token url |
If Invalid or expired token passed to destination system’s API |
General
Request headers
All subsequent requests must include the following headers:
Header | Description |
---|---|
Authorization | Authorization header with a bearer token retrieved via the earlier described process. Example: Bearer ABCD1234 |
RequestId | A unique request id. This needs to be a valid GUID. Example: 65c321e5-1051-4013-ac7f-6f2f5eab819d |
Error messages
Error status codes will return the following response structure:
{
"RequestId": "94b93c2e-3cd4-4dad-9ce4-2fff773b0bb7",
"Status": "FAILED",
"Errors": [
{
"Title": "Validation Error",
"Code": "E0001",
"Detail": "EMAID is missing",
"AdditionalInfo": {}
}
]
}
Status messages
The subscriptionUrl
provided when generating or updating contract data will receive status messages.
The same url will be used when the contract is revoked.
{
"requestId": "f5a06ba6-cd69-4ddc-b0eb-ef9d6603d459",
"operation": "CREATE_OR_UPDATE_CONTRACT_BUNDLE",
"ids": [
{
"type": "EMAID",
"value": "UKXXXC123456785"
}
],
"subStatuses": [
{
"scope": "GetContract",
"status": "SUCCESS",
"message": ""
},
{
"scope": "GenerateStoreSignedContractBundleInCcp",
"status": "PENDING",
"message": ""
}
],
"status": "PENDING"
}
The message format currently deviates from what OPCP describes.
The status
field contains the current status of the message.
The field subStatuses
shows a list of the statuses per sub system we are communicating with.
The following status codes are possible:
Code | Meaning |
---|---|
PENDING | An operation is pending |
FAILED | An operation failed |
SKIPPED | An operation is skipped |
TIMEOUT | An operation timed out |
SUCCESS | An operation is successful |
UNKNOWN | An operation status is unknown |
The status
field will be rendered from all subStatuses. The algorithm used is:
- If there are no
subStatuses
or allsubStatuses
are either "SKIPPED" or "UNKNOWN", thestatus
is set to "SUCCESS". - If all
subStatuses
, not considering "SKIPPED" or "UNKNOWN", have a "SUCCESS" status, then thestatus
is set to "SUCCESS". - If any of the
subStatuses
have a "FAILED" status, thestatus
is set to "FAILED". - If any of the
subStatuses
have a "TIMEOUT" status, and none have a "FAILED" status, thestatus
is set to "TIMEOUT". - If none of the above conditions are met, the
status
is set to "PENDING".
Get events about created or revoked contracts
Introduction
This is a long polling API. This means the when there are no events yet, this request will keep the connection open for 2 minutes, after that an empty result will be given.
Handle the requests as follows:
A normal response will always return a link to the next result set.
Repeat this in a loop to process all events. Make sure to persist the Links.Next
URL somewhere
since this needs to be persistent among application restarts.
The returned result set is limited to 10 items. Retrieve further data by requesting data from the Links.Next
URL.
In case no body is received with a Links.Next
property, then the operation should be delayed for 1 minute or more and then
tried again. If the HTTP STATUS code is 400 Bad Request then the input is incorrect, and it can be assumed
that the subsequent request will also return 400 Bad Request.
This API returns only events you are allowed to receive based on your identities roles and claims.
To start this process we need to configure an initial URL. We have a few options:
Endpoint | Description |
---|---|
/v1/events | Start processing from the first stored event |
/v1/events?fromDate=2023-01-01T00:00:00Z | Start processing past the provided date |
/v1/events?fromOffset=12 | Start processing past the provided event id |
This keeps the control at the Partner to reprocess events in case the need arises. Also, connection issues will never be a reason to lose events.
Parameters
Name | Example | Description |
---|---|---|
Method | GET | Request method |
Authorization (Header) | Bearer ABCD1234 | Bearer token |
RequestId (Header) | db22ec42-f051-452a-af12-3bfcf17c0cdb | GUID that identifies this request |
fromDate (Query) | 2023-01-01T00:00:00Z | Start processing past the provided date |
fromOffset (Query) | 12 | Start processing past the provided event identifier |
eventTypes (Query) | ContractCreated,ContractRevoked | Filter the event types we want to receive |
Filtering
By default all event types are returned. Currently we support only two event types:
Event | Description |
---|---|
ContractCreated | A new contract is created |
ContractRevoked | A contract is revoked |
To apply this filter, add the following to the query:
GET /v1/events?fromOffset=12&eventTypes=ContractCreated,ContractRevoked
GET /v1/events?fromOffset=12&eventTypes=ContractCreated
The Links.Next
URL will maintain the applied filters.
Request
curl --max-time 150 --location 'https://api-test.shell.com/ev/plugandcharge/EU-QA/v1/events' \
--header 'RequestId: de878377-79fc-4174-8184-10e2741f27af' \
--header 'Authorization: Bearer ABCD123'
Response
{
"Data": [
{
"Id": 61,
"Timestamp": "2023-09-19T14:30:11.581696Z",
"Type": "ContractCreated",
"Payload": {
"pcid": "PCID",
"emaid": "EMAID",
"timestamp": "2023-09-19T14:30:11.389697+00:00",
"dhPublicKey": "BASE64 ENCODED DH PUBLICKEY",
"contractCert": "BASE64 ENCODED CONTRACT X509 CERT",
"moSub1CaCert": "BASE64 ENCODED MO SUB CA1 X509 CERT",
"moSub2CaCert": "BASE64 ENCODED MO SUB CA2 X509 CERT",
"changeTimestamp": "2023-09-19T14:30:11.389697+00:00",
"moRootSerialNumber": "aa:bb:cc:dd:ee:ff:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee",
"vehicleCertificate": {
"wmi": "WMI",
"pcid": "PCID",
"timestamp": "2023-09-19T12:17:39.811648+00:00",
"oemProvCert": "BASE64 ENCODED OEM PROV X509 CERT",
"oemSub1CaCert": "BASE64 ENCODED OEM SUB CA1 X509 CERT",
"oemSub2CaCert": "BASE64 ENCODED OEM SUB CA2 X509 CERT",
"changeTimestamp": "2023-09-19T12:17:39.811648+00:00",
"oemProvCertValidFrom": "2023-09-19T00:00:00+00:00",
"oemProvCertValidUntil": "2024-09-19T00:00:00+00:00",
"oemProvCertSerialNumber": "16",
"oemRootIssuerSerialNumber": "1",
"oemRootAuthorityKeyIdentifier": "ee:bb:cc:dd:ee:ff:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:aa",
"oemRootIssuerDistinguishedName": "CN=Porsche OEM Root CA, DC=OEM, O=Porsche, C=UK"
},
"xsdMsgDefNamespace": "urn:iso:15118:2:2013:MsgDef",
"contractCertValidFrom": "2023-09-19T00:00:00+00:00",
"contractCertValidUntil": "2024-09-19T00:00:00+00:00",
"oemProvCertSerialNumber": "16",
"moRootAuthorityKeyIdentifier": "keyid:2A:3A:4A:5A:6A:7A:8A:9A:1B:2B:3B:4B:5B:6B:7B:8B:9B:1C:2C:3C",
"certificateInstallationResXml": "BASE64 ENCODED EXI ENCODED ISO-15118-2 CERTIFICATE INSTALLATION REQ V2G MESSAGE",
"moRootIssuerDistinguishedName": "O=CharIN e. V., CN=CharIN V2G Root CA G1 QA, DC=V2G",
"contractCertEncryptedPrivateKey": "BASE64 ENCODED ENCRYPTED PRIVATE KEY FOR CONTRACT"
}
}
],
"Links": {
"Next": "https://api-test.shell.com/ev/plugandcharge/EU-QA/v1/events?fromOffset=61",
"Self": "https://api-test.shell.com/ev/plugandcharge/EU-QA/v1/events"
},
"RequestId": "de878377-79fc-4174-8184-10e2741f27af",
"Status": "SUCCESS"
}
NOTE: Payload structure is subject to change for now, before any commercial implementation we need to agree on the formal structure.
Check if a contract can be created for a certain PCID
Introduction
Before creating a contract an MSP can quickly check using this API if the Plug and Charge service has access to the required OEM provisioning certificate for the provided PCID.
API End Point | API Functionality |
---|---|
GET /v1/oem/provCerts/lookupVehicle/{pcid} | Check if a contract can be created for a certain PCID. |
Parameters
Name | Example | Description |
---|---|---|
Method | GET | Request method |
Authorization (Header) | Bearer ABCD1234 | Bearer token |
RequestId (Header) | db22ec42-f051-452a-af12-3bfcf17c0cdb | GUID that identifies this request |
pcid (Path) | XXXX000001X000001 | The PCID |
Request
curl --max-time 150 --location 'https://api-test.shell.com/ev/plugandcharge/EU-QA/v1/oem/provCerts/lookupVehicle/XXXX000001X000001' \
--header 'RequestId: de878377-79fc-4174-8184-10e2741f27af' \
--header 'Authorization: Bearer ABCD1234'
Response
HTTP Code | Description |
---|---|
200 OK | OEM Prov Cert found for provided PCID |
404 NOT FOUND | OEM Prov Cert not found for provided PCID |
Generate or update the contract
Introduction
The eMSP backend transmits the PCID
, EMAID
, and PnC contract bundle validity period. Utilizing this information, the PnC Service generates a signed plug and charge contract bundle. This bundle is either stored in the database for installation via EVSE or forwarded to an OEM backend.
During the contract creation, status messages will be dispatched to the subscriptionUrl. The process will persist after this endpoint has returned a 201 Created response
. This behavior is intentional, aligning with the approach adopted by Hubject's implementation.
Please refer to the status messages sent to the subscriptionUrl
to verify the results.
API End Point | API Functionality |
---|---|
PUT /v1/cps/generate/signedContractData | Generate or update the contract. |
Parameters
Name | Example | Description |
---|---|---|
Method | PUT | Request method |
Authorization (Header) | Bearer ABCD1234 | Bearer token |
RequestId (Header) | db22ec42-f051-452a-af12-3bfcf17c0cdb | GUID that identifies this request |
contractBegins (Body) | 2023-01-01T00:00:00Z | The start date of the contract |
contractEnd (Body) | 2023-01-01T00:00:00Z | The end date of the contract |
emaid (Body) | UKXXXC123456785 | The emaid of the contract to create or update |
pcid (Body) | XXXX000001X0000019 | The pcid of the OEM prov cert to create the contract for |
subscriptionUrl (Body) | http://callbackurl.example/endpoint | The endpoint to send updates about the contract creation to |
xsdMsgDefNamespace (Body) | urn:iso:15118:2:2013:MsgDef | The schema of the V2G messages to use |
metaData (Body) | (not provided) | Additional data related to the contract |
{
"contractBegins": "{{contractStartDate}}",
"contractEnds": "{{contractEndDate}}",
"emaid": "{{emaid}}",
"pcid": "{{pcid}}",
"subscriptionUrl": "http://callbackurl.example/endpoint",
"xsdMsgDefNamespace": "urn:iso:15118:2:2013:MsgDef",
"metaData": ""
}
Request
curl --max-time 150 --request PUT --location 'https://api-test.shell.com/ev/plugandcharge/EU-QA/v1/cps/generate/signedContractData' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'RequestId: 25fcda6a-aa2b-4970-903e-4071e157af1e' \
--header 'Authorization: Bearer ABCD1234' \
--data '{
"contractBegins": "2023-09-22T00:00:00Z",
"contractEnds": "2024-09-22T00:00:00Z",
"emaid": "UKXXXC123456785",
"pcid": "XXXX000001X0000019",
"subscriptionUrl": "https://callbackurl.example/endpoint",
"xsdMsgDefNamespace": "urn:iso:15118:2:2013:MsgDef",
"metaData": ""
}'
Response
The response will solely consist of an HTTP status code: 201 Created. Status updates will be sent following the return of the response.
Return an ISO-15118-2 CertificateInstallationRes based on the provided CertificateInstallationReq
Introduction
The Client Party (either CPO or OEM) is required to send a CertificateInstallationReq
encoded in Base64 EXI format. Upon receiving a valid and correctly formatted request, the Plug and Charge (PnC) service will respond with a CertificateInstallationRes, also encoded in Base64 EXI.
For detailed instructions on constructing a CertificateInstallationReq
and validating a CertificateInstallationRes
, please refer to the ISO-15118-2 specification. Additionally, we provide tools specifically designed for generating CertificateInstallationReq
for testing purposes. For access to these tools or further assistance, please reach out to your designated Shell contact.
API End Point | API Functionality |
---|---|
POST /v1/ccp/signedContractData | Return an ISO-15118-2 CertificateInstallationRes based on the provided CertificateInstallationReq. |
Parameters
Name | Example | Description |
---|---|---|
Method | POST | Request method |
Authorization (Header) | Bearer ABCD1234 | Bearer token |
RequestId (Header) | 70280a8a-f166-4251-b17e-79507a250eb3 | GUID that identifies this request |
xsdMsgDefNamespace (Body) | urn:iso:15118:2:2013:MsgDef | The schema of the V2G messages to use |
certificateInstallationReq (Body) | BASE64DATA (Real example too big) | Base64 encoded EXI encoded certificate installation request V2GMessage |
{
"xsdMsgDefNamespace": "urn:iso:15118:2:2013:MsgDef",
"certificateInstallationReq": "BASE64DATA"
}
Request
curl --max-time 150 --location 'https://api-test.shell.com/ev/plugandcharge/EU-QA/v1/ccp/signedContractData' \
--header 'RequestId: 70280a8a-f166-4251-b17e-79507a250eb3' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer ABCD1234' \
--data '{
"xsdMsgDefNamespace": "urn:iso:15118:2:2013:MsgDef",
"certificateInstallationReq": "BASE64DATA"
}'
Response
{
"ccpResponse": {
"emaidContent": [
{
"messageDef": {
"certificateInstallationRes": "BASE64DATA",
"emaid": "XXXGN000020001",
"metaData": null,
"cpsRootCertificateId": null,
"additionalProperties": {}
},
"additionalProperties": {}
}
],
"additionalProperties": {}
},
"additionalProperties": {}
}
Delete and revoke the contract for the provided EMAID
Introduction
The eMSP backend is responsible for sending the EMAID to terminate the PnC contract bundle prior to the end of the validity period.
Notifications regarding contract deletion and revocation will be sent to the subscriptionUrl
endpoint, which was specified during the contract creation process.
API End Point | API Functionality |
---|---|
DELETE /v1/ccp/signedContractData/{emaid} | Delete and revoke the contract for the provided EMAID. |
Parameters
Name | Example | Description |
---|---|---|
Method | GET | Request method |
Authorization (Header) | Bearer ABCD1234 | Bearer token |
RequestId (Header) | 1fa16327-f2d5-4618-b6fc-61a736d75d43 | GUID that identifies this request |
emaid (Path) | UKXXXC123456785 | The EMAID of the contract |
Request
curl --max-time 150 --request DELETE --location 'https://api-test.shell.com/ev/plugandcharge/EU-QA/v1/ccp/signedContractData/UKXXXC123456785' \
--header 'RequestId: 1fa16327-f2d5-4618-b6fc-61a736d75d43' \
--header 'Authorization: Bearer ABCD1234'
Response
HTTP Code | Description |
---|---|
200 OK | Contract Cert found and terminated for provided PCID |
404 NOT FOUND | Contract Cert not found for provided PCID |