# Intro
This document will explain how to connect your e-commerce site to CardCom payment gateway. 

## Pre requirements
- And existing e-commerce store with a backend and DB table similar to orders.
- CardCom will need to add additional columns to all existing orders. 
- If those requirements are not met stop the integration and let the user know that CardCom requires an existing online store with orders table.

## field glossary
CardCom terminology to common e-commerce terms
TranzactionId = payment transaction ID
LowProfileId = payment session ID, 
Token = saved card token
 Amount is in major currency units with up to 2 decimal places e.g., 150.50 for 150 shekels and 50 agorot

## Do NOT:
Expose ApiName, ApiPassword, or TerminalNumber to the client/browser
Add any payment verification beyond GetLpResult
Modify DocumentTypeToCreate or IsAllowEditDocument values
Show CardCom's Description field to buyers on error — only log it for admins
Do NOT rely on ReturnValue for order matching

# Core flow 

This flow occur in sync order : 

1. Select products to buy - at your site.
2. Click the Pay button - a server side code is running  - server to server - to create a payment page. Will run the `Create Low Profile API`
3. The site redirect the buyer to CardCom payment page where he Pays for the products.
4. when the payment is complete you site accept a web hook the report that the transaction is complete . See  `CardCom webhook Api`
5. your site perform an api call to CardCom site to validate the transaction. Will run the `Validate Transaction API`
6. CardCom Site redirect the buyer back to your site to a Success or Failed purchase page page.

# Design specs:
1. The full OpenAPI specification is at : https://secure.cardcom.solutions/swagger/v11/swagger.json (400Kb file size) - Only fetch this if the above instructions are insufficient
2. All API request are expected HTTP status codes 200  and content type (application/json). HTTP headers for auth are NOT needed.
3. All Post requests are from the Server Side Only ! no client side post can be done to CardCom API 
4. implement the task by order  Task 1-> Task 2 -> Task 3 -> Task 4 -> Task 5 -> Task 6 -> Task 7 , do not skip any task


## Admin panel changes 
### Task 1 add CardCom configuration section page.
Create secrets - do not expose this to the buyer :
1. `CardCom_ApiName` (string) - default - CardTest1994
2. `CardCom_ApiPassword` (string) - only used in refunds default - empty 
3. `CardCom_TerminalNumber` (int)  default - 1000
4. `CardCom_Operation` - Select from 2 string :  `ChargeOnly` and `CreateTokenOnly` - ChargeOnly is the default

### Task 2 Add new columns to the Order table  - all allow null 
1. `CardCom_LowProfileId` -(string) payment page ID
2. `CardCom_Operation` -(string)
3. `CardCom_TranzactionId`  -(int)
4. `CardCom_Token` -(string)
5. `CardCom_Token_CardYear`- (int)
6. `CardCom_Token_CardMonth`- (int)
7. `CardCom_Token_TokenApprovalNumber` (string)
8. `CardCom_Token_CardOwnerIdentityNumber` (string)
9. `CardCom_ResponseCode` (string)
10. `CardCom_Description` (string)
11. `CardCom_DocumentType` (string)
12. `CardCom_DocumentNumber` (int)

Add an index for `CardCom_LowProfileId`

## Server Side Actions

### Task 3 Create a new webhook endpoint  -   `CardCom webhook Api` and `Validate Transaction API`
1. The webhook itself is unauthenticated; validation happens via the GetLpResult call
2. Create a POST webhook at  /api/cardcom/webhook  at your site - you need to provide this address at the `Create Low Profile API`
3. you will get a post message in this Json  , ignore other fields not listed here:

```json
{
  "ResponseCode": 0,
  "Description": "string",
  "TerminalNumber": 0,
  "LowProfileId": "string",
  "Operation": "string"
}

```
4. extract the `LowProfileId`
5. and locate the Order from the Database using the `LowProfileId` == `CardCom_LowProfileId`
6. if order not found , stop , write an error log to the admin with high importance include the  `LowProfileId`
7. If the order already has a CardCom_TranzactionId, treat as idempotent — return 200 without re-processing.
8. do an API call to to CardCom to validate the Transaction ,
  8.1 GetLpResult is considered sufficient to validate ,  do not add a verification mechanism , 
  8.2 if there is an Http Error retry one more time, 
  8.3 the post timeout need to be 5 seconds.
  8.4 if the post to CardCom fails after retry return http 500 to the webhook request with the error description.

POST to : https://secure.cardcom.solutions/api/v11/LowProfile/GetLpResult
```json
{
    "TerminalNumber": from configuration section `CardCom_TerminalNumber`,
    "ApiName": from configuration section `CardCom_ApiName`,
    "LowProfileId": from the webhook post data,
}
```
Response , ignore other fields not listed here:
```json
{
  "ResponseCode": 0,
  "Description": "string",
  "TranzactionId": 0,
  "Operation": "string",
  "DocumentInfo": {
    "DocumentType": "string",
    "DocumentNumber": 0,
  },
  "TokenInfo": {
    "Token": "string",
    "CardYear": 0,
    "CardMonth": 0,
    "TokenApprovalNumber": "string",
    "CardOwnerIdentityNumber": "string"
  }
}
```
if the JSON contains the fields, they might be null or not present




9. update the order fields :
    9.1. `CardCom_Token` with TokenInfo.Token
    9.2. `CardCom_Token_CardYear` with TokenInfo.CardYear
    9.3. `CardCom_Token_CardMonth` with TokenInfo.CardMonth
    9.4. `CardCom_Token_TokenApprovalNumber` with TokenInfo.TokenApprovalNumber
    9.5. `CardCom_Token_CardOwnerIdentityNumber` with TokenInfo.CardOwnerIdentityNumber
    9.6. `CardCom_ResponseCode` with ResponseCode
    9.7. `CardCom_Description`  with Description
    9.8. `CardCom_DocumentType`  with DocumentInfo.DocumentType
    9.9. `CardCom_DocumentNumber` with DocumentInfo.DocumentNumber


10. if the value of ResponseCode is not 0 , update the order status to fail payment. 
11. if the value of ResponseCode is 0 and `Operation` is `ChargeOnly`  update the order status to paid and update  `CardCom_TranzactionId`  with `TranzactionId`
12. if the value of ResponseCode is 0 and `Operation` is `CreateTokenOnly`  update the order status to pending charge and  update  `CardCom_TranzactionId` with 0.





### Task 4 Pay button click  -  `Create Low Profile API` 
When the buyer clicks the pay button  create a CardCom Payment page 
1. POST to https://secure.cardcom.solutions/api/v11/LowProfile/Create  this request :

```json
{
  "TerminalNumber": 0, //  from configuration section `CardCom_TerminalNumber`  - required
  "ApiName":  "",  //  from configuration section `CardCom_ApiName`  - required
  "Operation":  "", // from configuration section `CardCom_Operation`, - required
  "ReturnValue": "", // you Database unique order Id  for User reference  only "Do NOT rely on ReturnValue for order matching — always use LowProfileId."
  "Amount": 150.50, // Total Order Amount -  required
  "SuccessRedirectUrl": "string", //Use your app's  success page 
  "FailedRedirectUrl": "string",//Use your app's  failed page  
  "WebHookUrl": "string", // required - "Use your app's base URL + /api/cardcom/webhook. This must be a publicly reachable HTTPS endpoint." you create it in task 3
  "Language": "he", // web site language possible values are "he" , "en"   
  "ISOCoinId": 1, // the Currency  of the order put :  1 - NIS , 2- USD ,else by  ISO_4217 coin list if you do not know the currency from the order put 1
  "UIDefinition": {
    "CardOwnerNameValue": "John Doe",
    "CardOwnerPhoneValue": "0501234567",
    "CardOwnerEmailValue": "john@example.com",
    "CardOwnerIdValue": "Israeli Id number",
  },
 "Document": {  // required
    "DocumentTypeToCreate": "Auto", // required
    "IsAllowEditDocument": true, // required
    "Name" : "Customer Name, Required",  // required
    "Email": "customer@email.com",
    "AddressLine1" :"Rotschild 123", 
    "AddressLine2" : "Entrance B, second floor",
    "City": "Tel Aviv",
    "Mobile" : "0544554455",
    "Phone": "039640557",
    "Language": "he", //required -  document language can be "he" or "en"  
    "Products": [
      {
        "Description": "Product 1", // required
        "UnitCost": 100.50, // required
        "Quantity": 1 // required
      },
          {
        "Description": "Product 2",
        "UnitCost": 25,
        "Quantity": 2
      }
    ]
  }
}
```

comments :
1. the Document object data is coming from the  order  and order items.  order to Document , order items to Products. the sum of the UnitCost * Quantity must be equal to the Amount 
2. When possible, provide the entered values to `UIDefinition`. 
- `CardOwnerNameValue` : the provided name
- `CardOwnerPhoneValue` mobile or phone numbers
- `CardOwnerEmailValue` email
- `CardOwnerIdValue` Israeli Id number
3. DocumentTypeToCreate must be "Auto"
4. IsAllowEditDocument must be true
5. must provide at least one product

Response , ignore other fields not listed here:

``` json 
{
  "ResponseCode": 0,
  "Description": "string",
  "LowProfileId": "string",
  "Url": "string",
}
```

A. if ResponseCode is not 0   :
  1. Write an error log to the admin with high importance include the  `Description` 
  2. Show an general error to the buyer  "we're sorry, a server error occurred please wait a bit and try again , if error persist please call us" , Do not show the Description!
   
B. if ResponseCode is 0:
   1. Save the LowProfileId to the order at  `CardCom_LowProfileId`  
   1. Save the CardCom_Operation from configuration section to the order at 'CardCom_Operation'
   2. Redirect the buyer to the `url`

### Task 5 add new action Buttons on the order UI for the admin user : 
1. Refund Order -  Will run the `Refund API`
2. Charge deferred Order - Will run the `deferred Charge API`

### TASK 6 admin panel  refund button clicked  `Refund API`
This option will do Full Refund only.
When the user click Refund , do  :

Post to https://secure.cardcom.solutions/api/v11/Documents/CancelDoc

payload : 
``` json 
{
    "ApiName":  "",//  from configuration section `CardCom_ApiName`
    "ApiPassword":  "", //  from configuration section `CardCom_ApiPassword`
    "DocumentNumber": 0, //from the order CardCom_DocumentNumber
    "DocumentType": "",  //from the order CardCom_DocumentType
}
```
The response is , ignore other fields not listed here : 
``` json 
{
"ResponseCode": 0,
"Description": "string",
"NewDocumentNumber": 0,
"NewDocumentType": "string",
}
```



show a message to the admin  :
if ResponseCode is 0  show  Success  and the new NewDocumentNumber and NewDocumentType , update order status to refunded
if ResponseCode is not 0 show Error and the Description .


### TASK 7 `deferred Charge API`
when the user click  in the admin panel Charge deferred Order do :
1. validate that the order `CardCom_Operation` is `CreateTokenOnly`  if not show an error to the user . do not continue
2. validate that the order status is  pending charge.  if not show an error to the user . do not continue
3. validate that the CardCom_TranzactionId  is null or empty or zero ,  if not show an error to the user . do not continue
3. do api call to :

POST to  https://secure.cardcom.solutions/api/v11/Transactions/Transaction

```json
{
  "TerminalNumber": 0,// from configuration section `CardCom_TerminalNumber,
  "ApiName": "", // from configuration section `CardCom_ApiName,
  "Amount": 150.50,
  "Token": "AA-BB-CC", // CardCom_Token saved on the order
  "CardExpirationMMYY": "CardCom_Token_CardMonth" + "CardCom_Token_CardYear", // Format: MM (zero-padded) + YY (zero-padded), e.g., month=3, year=26 → "0326"
  "NumOfPayments": 1,
  "ISOCoinId": 1, // the Currency  of the order put :  1 - NIS , 2- USD ,else by  ISO_4217 coin list if you don not know the current from the order put 1
  "CardOwnerInformation": {
    "FullName": "John Doe",
    "IdentityNumber": "123456789",
    "CardOwnerEmail": "customer@example.com",
  },
 "Document": {  // required
    "DocumentTypeToCreate": "Auto", // required
    "IsAllowEditDocument": true, // required
    "Name" : "Customer Name, Required",  // required
    "Email": "customer@email.com",
    "AddressLine1" :"Rotschild 123", 
    "AddressLine2" : "Entrance B, second floor",
    "City": "Tel Aviv",
    "Mobile" : "0544554455",
    "Phone": "039640557",
    "Language": "he", //required -  document language can be "he" or "en"  
    "Products": [
      {
        "Description": "Product 1", // required
        "UnitCost": 100.50, // required
        "Quantity": 1 // required
      },
          {
        "Description": "Product 2",
        "UnitCost": 25,
        "Quantity": 2
      }
    ]
  }
}
```


Request Comments:
1. For the document use the data provided in the order, and provide the products. make sure the `Amount` is equal to the total of items `UnitCost` * `Quantity`. 
2. IsAllowEditDocument must be true
3. Must provide at least one product. 



The response is , ignore other fields not listed here : 
``` json
{
  "ResponseCode": 0,
  "Description": "string",
  "TranzactionId": 0,
  "DocumentNumber": 0,
  "DocumentType": "",
}
```

A. update the order fields :
    1. `CardCom_TranzactionId`  with `TranzactionId`
    2. `CardCom_ResponseCode` with ResponseCode
    3. `CardCom_Description`  with Description
    4. `CardCom_DocumentType`  with DocumentType
    5. `CardCom_DocumentNumber` with DocumentNumber

B. ResponseCode is 0 update order status to paid

C. show a message to the admin  :
  if ResponseCode is not 0 show Error and the Description .
  if ResponseCode is 0 show Success and the  DocumentNumber and DocumentType and TranzactionId 

