Sample code for 30+ languages & platforms
PureBasic

Egyptian eReceipt OAuth2 Client Credentials

See more Egypt eReceipt Examples

Get an OAuth2 access token for the Egyptian eReceipt REST API using client credentials (no interactivity with a web browser required).

Chilkat PureBasic Downloads

PureBasic
IncludeFile "CkHttpResponse.pb"
IncludeFile "CkHttp.pb"
IncludeFile "CkStringBuilder.pb"
IncludeFile "CkJsonObject.pb"
IncludeFile "CkHttpRequest.pb"

Procedure ChilkatExample()

    success.i = 0

    ; This example assumes the Chilkat API to have been previously unlocked.
    ; See Global Unlock Sample for sample code.

    http.i = CkHttp::ckCreate()
    If http.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    ; Note: Any provider of a REST API, such as the Egyptian government in this case, can make life 
    ; much easier for developers by providing one or more of the following in the API documentation:
    ; 
    ; 1) A sample CURL statement for each API call.
    ; 2) A Postman collection, or Swagger/OpenAPI specification file.
    ; 3) A sample of a raw HTTP request and response for each API call.
    ; 
    ; The sample CURL statements or raw HTTP request/responses do not need to comprehensively show all 
    ; possible options.  Providing a sample allows one to quickly make a successful API call.
    ; It also allows for code generation directly from the CURL, Postman collection, or raw request/response,
    ; and it tends to answer all questions about the format/structure of a request that, suprisingly,
    ; remain ambiguous or not obvious in other forms of documentation.

    req.i = CkHttpRequest::ckCreate()
    If req.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkHttpRequest::ckAddParam(req,"grant_type","client_credentials")
    ; Use your actual client ID and client secret...
    CkHttpRequest::ckAddParam(req,"client_id","d0394a9f-0607-40de-a978-2d3eb8375b04")
    CkHttpRequest::ckAddParam(req,"client_secret","6d62315e-d65a-4e41-9112-4195ea834edf")

    CkHttpRequest::ckAddHeader(req,"posserial","1234567899")
    CkHttpRequest::ckAddHeader(req,"pososversion","os")
    CkHttpRequest::ckAddHeader(req,"posmodelframework","1")
    CkHttpRequest::ckAddHeader(req,"presharedkey","03ac674216f3e1...")

    ; When writing this example, the documentation at https://sdk.invoicing.eta.gov.eg/ereceiptapi/01-authenticate-pos/
    ; shows us the HTTP verb and path (POST /connect/token), however,
    ; we don't see the actual domain where the request is to be sent.
    ; What are the endpoints???
    ; It took some searching, but we found some endpoints here:  https://sdk.invoicing.eta.gov.eg/faq/
    ; It's not immediately apparent which endpoint is to be used with a given API call.
    ; Why not just include the endpoint in the documentation for each REST API call?
    ; Endpoints are literally the #1 thing that needs to be known.
    ; They can't just be buried in a FAQ.  They should be up-front and obvious.
    ; 
    ; So.. we're guessing the endpoint is likely "https://invoicing.eta.gov.eg/connect/token"
    CkHttpRequest::setCkHttpVerb(req, "POST")
    CkHttpRequest::setCkContentType(req, "application/x-www-form-urlencoded")

    resp.i = CkHttpResponse::ckCreate()
    If resp.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    success = CkHttp::ckHttpReq(http,"https://invoicing.eta.gov.eg/connect/token",req,resp)
    If success = 0
        Debug CkHttp::ckLastErrorText(http)
        CkHttp::ckDispose(http)
        CkHttpRequest::ckDispose(req)
        CkHttpResponse::ckDispose(resp)
        ProcedureReturn
    EndIf

    sbResponseBody.i = CkStringBuilder::ckCreate()
    If sbResponseBody.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkHttpResponse::ckGetBodySb(resp,sbResponseBody)

    jResp.i = CkJsonObject::ckCreate()
    If jResp.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkJsonObject::ckLoadSb(jResp,sbResponseBody)
    CkJsonObject::setCkEmitCompact(jResp, 0)

    Debug "Response Body:"
    Debug CkJsonObject::ckEmit(jResp)

    respStatusCode.i = CkHttpResponse::ckStatusCode(resp)
    Debug "Response Status Code = " + Str(respStatusCode)
    If respStatusCode >= 400
        Debug "Response Header:"
        Debug CkHttpResponse::ckHeader(resp)
        Debug "Failed."
        CkHttp::ckDispose(http)
        CkHttpRequest::ckDispose(req)
        CkHttpResponse::ckDispose(resp)
        CkStringBuilder::ckDispose(sbResponseBody)
        CkJsonObject::ckDispose(jResp)
        ProcedureReturn
    EndIf

    ; If successful, the OAuth2 access token JSON looks like this:

    ; {
    ;   "token_type": "Bearer",
    ;   "access_token": "eyJraW......R2sbqrY",
    ;   "expires_in": "3600",
    ;   "scope": "..."
    ; }

    token_type.s = CkJsonObject::ckStringOf(jResp,"token_type")
    access_token.s = CkJsonObject::ckStringOf(jResp,"access_token")
    expires_in.s = CkJsonObject::ckStringOf(jResp,"expires_in")
    scope.s = CkJsonObject::ckStringOf(jResp,"scope")


    CkHttp::ckDispose(http)
    CkHttpRequest::ckDispose(req)
    CkHttpResponse::ckDispose(resp)
    CkStringBuilder::ckDispose(sbResponseBody)
    CkJsonObject::ckDispose(jResp)


    ProcedureReturn
EndProcedure