Marketplace Essentials

Learn the basics related to logging in, creating and managing surveys, and configuring your account

    PureText Guide - Decipher

     

    PureText Buyer API Integration in Decipher 


    OVERVIEW 


    This API checks for the Open-Ended (OE) survey responses to ensure data quality. It performs language comparison, AI-generated answer detection, exclusion list checks, and PureText deduplication. Below is the processing flow: 

    • Language Compare: Compares the language of the OE answer with the survey 
      language determined from the transaction ID
    • AI Detection: Detects whether the answer is AI-generated
    • Exclusion List: Checks if the answer is in an exclusion list of undesirable 
      responses
    • PureText Deduplication: Ensures the answer's uniqueness through 
      deduplication


    Pre-Requisites

    • Need to add below host names in the decipher directory. 
    • API Access token 
    • Valid transaction_id 
    • question_id: string or number or alpha numeric.  
      • Examples are Q1, S1 etc. 
    • text: Survey Response to validate.  
    • Endpoint 
      • POST /buyers/v3/transactions/ps_api_fail 

    How to get API access token from Market Place 

    If you are an API user, you already have a API access token or one could be created for 
    you. Please contact your Account manager to know how to get the access token for your 
    account. 

    How to Program in Decipher

    • Step 1: Create a res tag with the access-token as we need to use this at multiple 
      questions. Please see the orange highlighted in step 3 to know how we use res 
      tag in api call. 
    <res label="access_token">xxxxxxxx-xxxxxxxxxplace access token 
    herexxxxxxxxxxxxxxxx </res> 
    • Step 2: Call the API block at the end of the survey and update the question ids 
      (as highlighted in pink).  
      • If the question is a textarea question, please update the row text with the 
        question id.  
      • If it is an other specify option, please update the row text as 
        question_id#row#open. For example, there is a question Q2 and code r4 is 
        another specify option, then we need to use the syntax as Q2#r4#open
      • If the question type is a text question with multiple rows, then use the syntax 
        as question_id#row. For example, there is a question Q3 and codes r1 and 
        r2, then we need to use the syntax as Q3#r1 and Q3#r2.   
      • If the question type is text question with multiple rows and multiple columns, 
        then use the syntax as question_id#row#column. For example, there is a 
        question Q4 row r1 and column c1, then we need to use the syntax as 
        Q4#r1#c1

    API Block

     <suspend/> 
       <block label="PureText_Block_Set1" cond="list=='127'" sst="0"> 
         <note>----------------------API start----------------</note> 
         <exec when="init"> 
    def func(value): 
       return ' '.join(value.splitlines()) 
         </exec> 
         <suspend/> 
         <text  
        label="ndpRawSet1" 
        where="execute,survey,report"> 
           <title>Base question for Open ends punching</title> 
           <exec> 
    for eachrow in ndpRawSet1.rows: 
       str1 = eachrow.text.split("#") 
       if len(str1[0]) gt 0: 
        if len(str1)==1: 
                 if allQuestions[str1[0]].any and len(allQuestions[str1[0]].val) gt 0: 
                     eachrow.c2.val = func(allQuestions[str1[0]].unsafe_val)  
                     eachrow.c1.val = str1[0]

        if len(str1)==2: 
                 if allQuestions[str1[0]].attr(str(str1[1])).any and len(allQuestions[str1[0]].attr(str(str1[1])).val) gt 0: 
                     eachrow.c2.val = func(allQuestions[str1[0]].attr(str(str1[1])).unsafe_val) 
                     eachrow.c1.val = str1[0]+"_"+str1[1] 
        if len(str1)==3: 
            if str1[2]=="open": 
                     if allQuestions[str1[0]].attr(str(str1[1])).attr(str(str1[2])) and allQuestions[str1[0]].attr(str(str1[1])) 
    and len(allQuestions[str1[0]].attr(str(str1[1])).attr(str(str1[2]))) gt 0: 
                         eachrow.c2.val = func(allQuestions[str1[0]].attr(str(str1[1])).unsafe_open) 
                         eachrow.c1.val = str1[0]+"_"+str1[1]+"_open" 
            else: 
                     if allQuestions[str1[0]].attr(str(str1[1])).attr(str(str1[2])).any and 
    len(allQuestions[str1[0]].attr(str(str1[1])).attr(str(str1[2])).val) gt 0: 
                         eachrow.c2.val = func(allQuestions[str1[0]].attr(str(str1[1])).attr(str(str1[2])).unsafe_val) 
                         eachrow.c1.val = str1[0]+"_"+str1[1]+"_"+str1[2] 
           </exec> 

           <row label="r1">Q1</row> 
           <row label="r2">Q2#r4#open</row> 
           <row label="r3">Q3#r1</row> 
           <row label="r4">Q3#r2</row> 
           <row label="r5">Q3#r3</row> 
           <row label="r6"/> 
           <row label="r7"/> 
           <row label="r8"/> 
           <row label="r9"/> 
           <row label="r10"/> 
           <row label="r11"/> 
           <row label="r12"/> 
           <row label="r13"/> 
           <row label="r14"/> 
           <row label="r15"/> 
           <row label="r16"/> 
           <row label="r17"/> 
           <row label="r18"/> 
           <row label="r19"/> 
           <row label="r20"/> 
           <col label="c1">qid</col> 
           <col label="c2">text</col>

         </text> 

         <suspend/> 

         <suspend/> 

         <text  
        label="PTstatusapiSet1" 
        randomize="0" 
        where="execute,survey,report"> 
           <title>Status from API call</title> 
         </text> 

         <suspend/> 

         <exec> 
    #body 
    question_id1 = ndpRawSet1.r1.c1.val 
    question_id2 = ndpRawSet1.r2.c1.val 
    question_id3 = ndpRawSet1.r3.c1.val 
    question_id4 = ndpRawSet1.r4.c1.val 
    question_id5 = ndpRawSet1.r5.c1.val 
    question_id6 = ndpRawSet1.r6.c1.val 
    question_id7 = ndpRawSet1.r7.c1.val 
    question_id8 = ndpRawSet1.r8.c1.val 
    question_id9 = ndpRawSet1.r9.c1.val 
    question_id10 = ndpRawSet1.r10.c1.val 
    question_id11 = ndpRawSet1.r11.c1.val 
    question_id12 = ndpRawSet1.r12.c1.val 
    question_id13 = ndpRawSet1.r13.c1.val 
    question_id14 = ndpRawSet1.r14.c1.val 
    question_id15 = ndpRawSet1.r15.c1.val 
    question_id16 = ndpRawSet1.r16.c1.val 
    question_id17 = ndpRawSet1.r17.c1.val 
    question_id18 = ndpRawSet1.r18.c1.val 
    question_id19 = ndpRawSet1.r19.c1.val 
    question_id20 = ndpRawSet1.r20.c1.val


    text1 = ndpRawSet1.r1.c2.val 
    text2 = ndpRawSet1.r2.c2.val 
    text3 = ndpRawSet1.r3.c2.val 
    text4 = ndpRawSet1.r4.c2.val 
    text5 = ndpRawSet1.r5.c2.val 
    text6 = ndpRawSet1.r6.c2.val 
    text7 = ndpRawSet1.r7.c2.val 
    text8 = ndpRawSet1.r8.c2.val 
    text9 = ndpRawSet1.r9.c2.val 
    text10 = ndpRawSet1.r10.c2.val 
    text11 = ndpRawSet1.r11.c2.val 
    text12 = ndpRawSet1.r12.c2.val 
    text13 = ndpRawSet1.r13.c2.val 
    text14 = ndpRawSet1.r14.c2.val 
    text15 = ndpRawSet1.r15.c2.val 
    text16 = ndpRawSet1.r16.c2.val 
    text17 = ndpRawSet1.r17.c2.val 
    text18 = ndpRawSet1.r18.c2.val 
    text19 = ndpRawSet1.r19.c2.val 
    text20 = ndpRawSet1.r20.c2.val 

    transaction_id = transaction_id 

    datadict = '''{ 
       "transaction_id": "%s", 
       "questions": [{"question_id": "%s","text": "%s"},{"question_id": "%s","text": "%s"},{"question_id": 
    "%s","text": "%s"},{"question_id": "%s","text": "%s"},{"question_id": "%s","text": "%s"},{"question_id": 
    "%s","text": "%s"},{"question_id": "%s","text": "%s"},{"question_id": "%s","text": "%s"},{"question_id": 
    "%s","text": "%s"},{"question_id": "%s","text": "%s"},{"question_id": "%s","text": "%s"},{"question_id": 
    "%s","text": "%s"},{"question_id": "%s","text": "%s"},{"question_id": "%s","text": "%s"},{"question_id": 
    "%s","text": "%s"},{"question_id": "%s","text": "%s"},{"question_id": "%s","text": "%s"},{"question_id": 
    "%s","text": "%s"},{"question_id": "%s","text": "%s"},{"question_id": "%s","text": "%s"}] 
    }''' %(transaction_id, question_id1,text1, question_id2,text2, question_id3,text3, question_id4,text4, 
    question_id5,text5, question_id6,text6, question_id7,text7, question_id8,text8, question_id9,text9, 
    question_id10,text10, question_id11,text11, question_id12,text12, question_id13,text13, 
    question_id14,text14, question_id15,text15, question_id16,text16, question_id17,text17, 
    question_id18,text18, question_id19,text19, question_id20,text20) 

    headerdict={'Content-Type': 'application/json; charset=utf-8','access-token':  res.access_token }

         </exec> 

         <logic label="lg_apiSet1" api:data="datadict" api:headers="headerdict" api:method="POST" 
    api:url="https://spectrumsurveys.com/buyers/v3/transactions/ps_api_fail" uses="api.1"> 
           <title>API Integration</title></logic> 
         <exec cond="PTstatusapiSet1.val in ['',None]"> 
    if lg_apiSet1.status == 200: 
      PTstatusapiSet1.val = str(lg_apiSet1.status) 
      PTapiSet1.val = lg_apiSet1.r;    
    else: 
       PTstatusapiSet1.val = "failure of api" 
         </exec> 

         <suspend/> 

         <textarea  
        label="PTapiSet1" 
        where="execute,survey,report"> 
           <title>Hidden Var</title> 
         </textarea> 

         <suspend/> 

         <text  
        label="PTR_Set1" 
        altlabel="PT_" 
        size="40" where="execute,survey,report"> 
           <title>Hidden in LIVE.</title> 
           <exec> 
    if lg_apiSet1.status == 200: 
    data = lg_apiSet1.r['data'] 
    paf = agr = ir = dr = lm = 0 
    a_paf = [] 
    a_agr = [] 
    a_ir = [] 
    a_dr = [] 
    a_lm = [] 
    a_oti = []

    for i in range(len(data)):  
     qid = data[i]['question_id'] 
     oti = data[i]['original_transaction_id'] 
      
     if oti != None: 
      qidoti = qid+":"+oti 
      a_oti.append(qidoti) 
       
     if data[i]['puretext_api_fail'] == 1:     
      paf = paf+1 
      a_paf.append(qid) 
     if data[i]['ai_generated_response'] == 1: 
      agr = agr+1  
      a_agr.append(qid)   
     if data[i]['incoherent_response'] == 1: 
      ir = ir+1 
      a_ir.append(qid)   
     if data[i]['duplicate_response'] == 1: 
      dr = dr+1 
      a_dr.append(qid)     
     if data[i]['language_mismatch'] == 1: 
      lm = lm+1 
      a_lm.append(qid) 
    if paf ge 1: 
     PTR_Set1.puretext_api_fail_Result_Set1.val = paf 
     a_paf_r = [] 
     [a_paf_r.append(x) for x in a_paf if x not in a_paf_r] 
     PTR_Set1.puretext_api_fail_QIDs_Set1.val = ', '.join(a_paf_r) 
    if agr ge 1: 
     PTR_Set1.ai_generated_response_COUNT_Set1.val = agr 
     a_agr_r = [] 
     [a_agr_r.append(x) for x in a_agr if x not in a_agr_r]   
     PTR_Set1.ai_generated_response_QIDs_Set1.val = ', '.join(a_agr_r)  
    if ir ge 1: 
     PTR_Set1.incoherent_response_COUNT_Set1.val = ir 
     a_ir_r = [] 
     [a_ir_r.append(x) for x in a_ir if x not in a_ir_r]

     PTR_Set1.incoherent_response_QIDs_Set1.val = ', '.join(a_ir_r)   
    if dr ge 1: 
     PTR_Set1.duplicate_response_COUNT_Set1.val = dr 
     a_dr_r = [] 
     [a_dr_r.append(x) for x in a_dr if x not in a_dr_r] 
     PTR_Set1.duplicate_response_QIDs_Set1.val = ', '.join(a_dr_r)  
    if lm ge 1: 
     PTR_Set1.language_mismatch_COUNT_Set1.val = lm 
     a_lm_r = [] 
     [a_lm_r.append(x) for x in a_lm if x not in a_lm_r] 
     PTR_Set1.language_mismatch_QIDs_Set1.val = ', '.join(a_lm_r) 
    if len(a_oti) ge 1: 
     a_oti_r = [] 
     [a_oti_r.append(x) for x in a_oti if x not in a_oti_r] 
     PTR_Set1.original_transaction_dedupe_id.val = ', '.join(a_oti_r) 
           </exec> 

           <row label="puretext_api_fail_Result_Set1">puretext_api_fail_Result_Set1</row> 
           <row label="puretext_api_fail_QIDs_Set1">puretext_api_fail_QIDs_Set1</row> 
           <row label="ai_generated_response_COUNT_Set1">ai_generated_response_COUNT_Set1</row> 
           <row label="ai_generated_response_QIDs_Set1">ai_generated_response_QIDs_Set1</row> 
           <row label="incoherent_response_COUNT_Set1">incoherent_response_COUNT_Set1</row> 
           <row label="incoherent_response_QIDs_Set1">incoherent_response_QIDs_Set1</row> 
           <row label="duplicate_response_COUNT_Set1">duplicate_response_COUNT_Set1</row> 
           <row label="duplicate_response_QIDs_Set1">duplicate_response_QIDs_Set1</row> 
           <row label="language_mismatch_COUNT_Set1">language_mismatch_COUNT_Set1</row> 
           <row label="language_mismatch_QIDs_Set1">language_mismatch_QIDs_Set1</row> 
           <row label="original_transaction_dedupe_id">original_transaction_dedupe_id</row> 
         </text> 

         <suspend/> 

         <radio  
        label="PT_apiSet1" 
        optional="1" 
        where="execute,survey,report"> 
           <title>Hidden in LIVE</title> 
           <exec>
    PT_apiSet1.val = PT_apiSet1.r2.index 
    if PTR_Set1.puretext_api_fail_Result_Set1.any and len(PTR_Set1.puretext_api_fail_Result_Set1.val) ge 1: 
    PT_apiSet1.val = PT_apiSet1.r1.index 
           </exec> 

           <row label="r1">Fail</row> 
           <row label="r2">Pass</row> 
         </radio> 

         <suspend/> 

         <term label="PureTextSet1Term" cond="PT_apiSet1.r1">Term at PT Set1</term> 
       <suspend/> 

         <note>----------------------API End----------------</note>      
     </block> 

     <suspend/>

     

     
     

     

    Result

    Result: Results are stored in 11 flags, and shows where the respondent has failed.  

    1. PT_puretext_api_fail_Result_Set1: Indicates the count of all the flags where the respondents failed. For example, if the respondent was flagged due to incoherent response at Q1 and language mismatch at Q2. Then this count will be 2 (consolidated count). 
    2. PT_puretext_api_fail_QIDs_Set1: Indicates the question ids (with comma separation) which the respondents failed.  For example, if the respondent was flagged due to incoherent response at Q1 and language mismatch at Q2. Then it shows “ Q1, Q2” 
    3. PT_ai_generated_response_COUNT_Set1: Indicates the count of all questions where the respondent failed due to AI generated text.  
    4. PT_ai_generated_response_QIDs_Set1: Shows the list of all question ids with the comma separation where the respondent failed due to AI generated text. 
    5. PT_incoherent_response_COUNT_Set1: Indicates the count of all questions where the questions failed due to incoherent/junk response.   
    6. PT_incoherent_response_QIDs_Set1: Shows the list of all question ids with the comma separation where the questions are failed due to incoherent/junk response. 
    7. PT_duplicate_response_COUNT_Set1: Indicates the count of all questions where the questions failed due to duplicate response.  
    8. PT_duplicate_response_QIDs_Set1: Shows the list of all question ids with the comma separation where the questions failed due to duplicate response. 
    9. PT_language_mismatch_COUNT_Set1: Indicates  the count of all questions where the questions are failed due to language mismatch.  
    10. PT_language_mismatch_QIDs_Set1:  Shows the list of all question ids with the comma separation where the questions are failed due to language mismatch. 
    11. PT_original_transaction_dedupe_id: Only in case of PT Deduplicate fail, this shows the list of all question ids and the original transaction_id that was duplicated from. 

    Finally, the consolidated flag (PT_apiSet1) indicates fail/pass options for the entire transaction. It shows fail if the any flag fails from the above 11 flags. And pass if all the flags are passed. The pass/fail criteria can be programmed based on client’s acceptability criteria. 
     


    Termination Process

    The response returned Fail by PureText API can be considered for termination by adding the termination tag at the end of the script (Please see the green highlighted lines in step 3). The client may also choose to just collect the data as a flag for a post study decision on its handling.  
     

    • Step 3: ( in case of termination) Update the termination redirect for this API failure as 
      shown below for PureSpectrum sample.

    Updating Termination Redirect

    <samplesource keyring="sys/ps" list="127" sign="out"> 
       <title>Pure Spectrum</title> 
       <invalid>You are missing information in the URL. Please verify the URL with the original invite.</invalid> 
       <completed>It seems you have already entered this survey.</completed> 
       <var name="transaction_id" unique="1"/> 
       <var name="PSID"/> 
       <var name="supplier_id"/> 

       <exit cond="qualified" 
    url="https://spectrumsurveys.com/surveydone?st=21&transaction_id=${transaction_id}"/> 

       <exit cond="terminated and PT_apiSet1.r1" 
    url="https://spectrumsurveys.com/surveydone?st=84&transaction_id=${transaction_id}"/> 

       <exit cond="terminated and (NDPSpeederCheck.r1 or NDPSTRLNRCheck.r1 or NDPTRAPFLAG2.r1)" 
    url="https://spectrumsurveys.com/surveydone?st=20&transaction_id=${transaction_id}"/> 

       <exit cond="terminated" 
    url="https://spectrumsurveys.com/surveydone?st=18&transaction_id=${transaction_id}"/> 

       <exit cond="overquota" 
    url="https://spectrumsurveys.com/surveydone?st=17&transaction_id=${transaction_id}"/> 
     </samplesource> 
    </samplesources> 

     
     

     

    Result Screenshot for Reference

    Additional Information

    PureText can bulk process a maximum of 20 open ends. Upon exceeding this limit, please follow the steps outlined below.  
    1. Create another block with the same code just by replacing the “Set1” with the 
    “Set2” ... “SetN”. 
    2. Follow the same steps 2 – 4 again.  
    3. In step 4, please update the condition as below – 

    <exit cond="terminated and (PT_apiSet1.r1 or PT_apiSet2.r1) " 
    l="https://spectrumsurveys.com/surveydone?st=84&transaction_id=${transaction_id}"/> 

     

    Possible Errors

     

    Give feedback about this article