Iterating a list of users in postman

Hello! I am trying to use postman to iterate over a list of users to re-send an activation email. I am just diving into the functionality of Postman and am unable to find this. I have a Lifecycle POST url that is working when I do it one by one. Is there a way to have an array of userIds so I don’t have to set the userId over 100 times?

Thanks!

1 Like

Hi @jb3rgman

Welcome to the community! Its great to have you here.

What I would suggest for this is Postman Runner. With Postman Runner, you can create a json or csv file with those userIds, then in your Postman Request, set the userId variable (that refers to the data in your file) to the appropriate place in your POST Request, and the execute the Runner.

Have a look at the Postman Requests and Runner documentation here.

https://learning.postman.com/docs/postman/sending-api-requests/requests/

https://learning.postman.com/docs/postman/collection-runs/intro-to-collection-runs/

Additionally, I created a video to cover Postman Runner that may be helpful as well.

Let us know if you can get it working!

Regards,
Orest

1 Like

Thanks for the response @odanylewycz! Glad to be here. Let me run through this and I will post back with my results!

1 Like

@odanylewycz,
This worked perfectly. I was able to create the list and iterate over all the values. The hardest part was getting the data. I tried to get it with Postman but no luck. Thank you again for the assistance!

Josh

1 Like

Awesome! I’m glad you could get it working!

And I’m curious, how were you getting the data? If it was via another web request, we could have scripted that out using its built in Nodejs environment, and fed that to your POST request for your activation emails.

Possibly something for the future!

Best Regards,
Orest

How I got the data was probably not the best way. I was trying to run an API call and filter on an attribute. I was able to do this but the data that was returned was the entire user profile. I was unable to get the email address so I just copied and pasted. I will need to do this again in the future. Can I use postman to query the data I need and then run the POST?

Thanks for the explanation.

Reading that, it sounds possible to query, filter, and run the activation all automated via postman.

If possible, could you share the following:

Request used to obtain user profiles
Sample response of above request
Request to send reactivation

With the above, I can figure out if it’s possible and even provide a sample solution for you.

Best,
Orest

@odanylewycz Here is the data you requested.

GET request


url/api/v1/users?filter=status eq "PROVISIONED"

Sample data


{
    "id": "xxxxxxxx",
    "status": "PROVISIONED",
    ...
    "profile": {
        "lastName": "Smith",
        "firstName": "John",
        "email": "john.smith@email.com"
        ...
    }

POST request


url/api/v1/users/{{userId}}/lifecycle/reactivate?sendEmail=true

{{userId}} is the header of the CSV and this lists down all the email addresses.

So basically I would like to GET all the PROVISIONED users. Only return their email and POST to that value.

Perfect! So what we can do is create a Postman Request with the “GET” you specified.

Then, we can parse the results in the test script, to obtain the userId, and create a new POST request in the test script to send off the reactivation email.

pm.test("Parse UserIDs And Send Activation Email", function () {

var users = JSON.parse(responseBody);

users.forEach(function (user) {

console.log(user.id)

var url = "domain.com" + "/api/v1/users/" + user.id + "/lifecycle/reactivate?sendEmail=true"

pm.sendRequest({
url: url,
method: "POST",
header: {
    'Authorization': 'Basic ' + btoa('username:password')
}
}, function (err, res) {
console.log("Sent Activation!")
});
})
});

Note, the above assumes you use basic authentication. If some other form of authentication, add it to the header.

But with this, it will perform the POST the sent the activation email to any user to comes in the response for the GET request, you specify in your Postman collection.

Let me know if this works for you!

Regards,
Orest

@odanylewycz Thank you for this information. I need to see how to run a test script. Im still a noob and learning! But if that will work I will definitely use in the future!

1 Like

You’re welcome, I hope it works!

It’s good to always be learning :blush:.

Whenever you start getting into test scripts, I also made a video on using this within Postman.

I hope this helps too!

All the best,
Orest

1 Like

@odanylewycz, first thank you for the detailed response and code examples for this iterative use case.

I’m working through a similar project, and this thread has been very helpful for me.
I have a bit a twist; however, that is giving me difficulties and would really appreciate your insight. I have a csv of automotive service records and need to write them into a new system via its API.

I have a collection consisting of two POST requests:

  1. Creates a service_entry for a vehicle (this represents a single service event) and writes basic info related to the vehicle, date, odometer, and vendor who performed the work.

  2. The other creates a single line item w/in that service_entry- called a service_task. A given service entry can have multiple line items that represent a complete service event.

I’m having trouble with 2 parts of this project:
First, some service entries will have a single service_task while others will have multiple service_tasks and I want to be sure all are added before moving onto the next service entry. Conditional statement (?)
Second, I’m having issues obtaining the id from the JSON response of my first request that is needed to create the line item entries.

Note: This sequence is a requirement of the API I’m working with, as I can’t create the entire entry in the way the user wants in one attempt from just the /service_entry endpoint.

Details:

  • The first POST references a {{vehicle_id}} variable - I’m using the .csv import data features of Postman to read in these values and put them into the url of the POST that creates the service entry. This is working for me :+1:

  • When it’s time to move onto the first service_task run, the {{id}} from the created service_entry is needed in the URL. This is the script I have - my intent is for this to fetch the {{id}} variable so I can use it in my next call.


Unfortunately, I’m getting a “ReferenceError: id is not defined” error - so I don’t think I’m referencing the JSON variable response correctly here.

Thank you and standing by for any questions!! -

1 Like

UPDATE
@odanylewycz
I found this article: How to save a value from response as a environment variable

and using the guidance there - thanks @dannydainton!
I changed my test script from this (which was not working:

// Test for successful command
pm.test("Status 201, service entry created!", function () { pm.response.to.have.status(201); });

pm.test("Checking for service_entry_id", function () {
    // Parse the response    
    pm.expect(pm.response.json())
        .to.nested.include({
            'args.id': JSON.stringify(pm.iterationData.get('id'))
        });
    console.log("Creating new line item service_task for entry: " + pm.iterationData.get("id"));    
});

postman.setNextRequest("Create Service Line Item");

To this- which works to set the {{id}} variable in my subsequent request for the collection run :slight_smile: :

// Test for successful command
pm.test("Status 201, service entry created!", function () { pm.response.to.have.status(201); });

// Parse JSON - set environment variable!
var jsonData = JSON.parse(responseBody);
pm.environment.set("id", jsonData["id"]);

postman.setNextRequest("Create Service Line Item");

Any tips or ideas on the first question regarding adding a conditional statement or loop to accomodate service entries that have > 1 service_task would be greatly appreciated.
Thanks!

  • J

Hi @j_who!

Thank you very much for the kind words, I’m really glad you were able to get help from my earlier response!

I am also glad @dannydainton’s content was helpful. He does have a lot of good stuff out there!

As for the issue you are still dealing with. How does the service_task look like? Is it a json attribute with a string value, integer value, an object, or an array (array of strings or array of integers)? I’m asking to see what the identifying criteria is for multiple service tasks. Are these service tasks coming from your csv file, or are you doing an API call to obtain them?

From what I see, it seems like you are pulling a service_task_id from the csv file. From here, I would check how many service_task_ids there are, which should then indicate if there are multiple or not.

Without the format of multiple services task ids, it’ll be difficult to provide any code that would check to see if you’re using a single or multiple service_task_ids.

Please provide that info if you can and I’ll do my best to help!

Thanks again!
Orest

1 Like

@odanylewycz - thanks so much - here are answers to your question - I hope you find them helpful. Lmk if anything isn’t clear and I can expand.

WORK ORDER LINE ITEM FIELDS

(I’ve taken this directly from the online documentation)

Note: I have been able to successfully create service task line items using a service_task_id field instead of using item_type and item_id as outlined in two separate fields below. (This wasn’t intentional).

Sample Request Body
https://{{base_url}}/api/v2/service_entries/{{id}}/service_entry_line_items

The {{id}} is populated from the earlier POST that creates the new service_entry

{
	"type": "ServiceEntryServiceTaskLineItem",
	"service_task_id": 3191105,
	"description": "Instrument Panel Electrical, Service Subcategory ID = S55",
	"labor_cost": $50.00,
	"parts_cost": $40.00
}
Field Description
type string (required, string)
Used to denote what type of line item this is. Currently, the only valid value is WorkOrderServiceTaskLineItem .
item_type string (required, editable)
Used in conjunction with item_id denotes the class name for the item association. Valid values are "ServiceTask" .
item_id integer (required, editable)
Used in conjunction with item_id , denotes the foreign key for the item association. This is typically the ServiceTask id.
description text (optional, editable)
Free text field for item description.
labor_cost double (optional, editable)
Total labor cost for this line item. If there are labor line items present, the labor cost will be calculated from the sum of their totals and this value will be overwritten.
parts_cost double (optional, editable)
Total parts cost for this line item. If there are part line items present, the labor cost will be calculated from the sum of their totals and this value will be overwritten.

The service_task_id is a reference to a large data set of service items that can be applied to any service_entry. This library of id’s is fixed and can be queried by w/ a GET to the API.

Currently, I’m using a csv for my data file, and have the service data organized with one service_entry per row, with multiple columns to account for any particular entry that has more than 1 service_task.

Hi @j_who!

Thanks for always being so detailed, its definitely helpful.

So, if you can confirm with me, when you have a service entry with more that one service task, you create an individual column for every entry. So you have type,service_task_id,description,labor_cost,parts_cost, and then you repeat those columns for the second service task, correct? Just trying to be sure I have the proper understanding.

If my understanding is correct, what I would do is pre-format the json in the csv file, and then reference that as a variable.

So to further assist, how does your service_entry POST request look like? More specifically, where does the service_task go in the body of the POST request?

What I am thinking is you create a column called “service_tasks” and in that column, you place all the service tasks for that service entry. For example you can have one service_tasks set to:

[ {
	"type": "ServiceEntryServiceTaskLineItem",
	"service_task_id": 3191105,
	"description": "Instrument Panel Electrical, Service Subcategory ID = S55",
	"labor_cost": $50.00,
	"parts_cost": $40.00
} ]

And another to:

   [ {
    	"type": "ServiceEntryServiceTaskLineItem",
    	"service_task_id": 3191105,
    	"description": "Instrument Panel Electrical, Service Subcategory ID = S55",
    	"labor_cost": $50.00,
    	"parts_cost": $40.00
    },
    {
    	"type": "ServiceEntryServiceTaskLineItem",
    	"service_task_id": 3191125,
    	"description": "Instrument Panel Dash, Service Subcategory ID = S65",
    	"labor_cost": $55.00,
    	"parts_cost": $44.00
    } ]

So that when you reference the variable {{service_tasks}} in your POST request body, you get all the tasks you need, regardless if there are multiple or not. So it should look like this:

{
    "type": "WorkOrderServiceTaskLineItem",
    "item_type": "ServiceTask",
    "item_id": 12345,
    "description": "Replacing brake pads",
    "issue_ids[]": 1,
    "issue_ids[]": 2,
    "work_order_sub_line_items_attributes":{{service_tasks}}
  }

That is assuming the above is your POST request, and that’s coming from the link you referenced. Hopefully this makes sense and that it works for you! Let me know if it does.

Regards,
Orest

Continued thanks for helping me with this!

@odanylewycz, :point_up: yes that is how I have been structuring my data csv.

Regarding the POST request that creates the service_entry I have my request body set up as a form-data type in Postman currently - I did this just to visually check all my variables and write descriptions in for things as I troubleshoot this.

From the documentation, I thought I would be able to pass the service_task(s) by ID into my request body of the first service_entry request based on the API’s documentation

curl -X POST \
  http://localhost:7000/api/v2/service_entries/ \
  -H 'account-token: 12345' \
  -H 'authorization: Token token=abcdefg' \
  -F vehicle_id=153 \
  -F completed_at=2018-03-05 \
  -F 'service_task_ids[]=123' \
  -F 'service_task_ids[]=246' \
  -F 'meter_entry_attributes[value]=150000' \
  -F total_amount=1500.53

however; I was disapointed to find out after testing that this outcome in the software isn’t an acceptable solution. This is for 2 main reasons:

  1. The service_task isn’t able to be broken out into “parts” and “labor” w/ the available service_entry fields. Each service_task has it’s own values for each, regardless of how many tasks are in a single service_entry.
  2. There is an additional service task description field available when POST is sent to an existing service_entry that is important to populate. There is a description for each service_task.

These keys are only in the line item support for service entries, which only works after a service_event already exists. I never thought about what you’re suggesting and was excited to try it. :point_down:


If my understanding is correct, what I would do is pre-format the json in the csv file, and then reference that as a variable.

From your suggestion above, I’m not completely understanding what you mean by “preformating my JSON in the csv”. I tested pasting the following test JSON into the csv cell column service_task_ids

[ { "type": "ServiceEntryServiceTaskLineItem", "service_task_id": 3191105, "description": "Instrument Panel Electrical, Service Subcategory ID = S55", "labor_cost": $50.00, "parts_cost": $40.00 } ]

The response was was successful (201), but there isn’t any service_task data line items in the actual service_entry at all. (I verified this in the software UI as well…). Here is the full JSON response of this test:

{
    "id": 6867874,
    "vehicle_id": 984019,
    "completed_at": "2020-01-13T00:00:00.000-08:00",
    "total_amount_cents": 0,
    "currency": "USD",
    "created_at": "2020-03-05T14:47:32.770-08:00",
    "updated_at": "2020-03-05T14:47:32.882-08:00",
    "vendor_id": 1036303,
    "reference": "1234",
    "account_id": 28651,
    "custom_fields": {
        "account_catagory": "{{account_category}}",
        "expense_label_temp": "N-DLN",
        "repair_order_id": "PO9876"
    },
    "tax_1_percentage": 0.0,
    "tax_2_percentage": 0.0,
    "labor_subtotal_cents": 0,
    "parts_subtotal_cents": 0,
    "tax_1_cents": 500,
    "tax_2_cents": 0,
    "tax_1_type": "fixed",
    "tax_2_type": "percentage",
    "documents_count": 0,
    "comments_count": 0,
    "work_order_id": null,
    "vehicle_archived_at": null,
    "images_count": 0,
    "started_at": null,
    "discount_type": "fixed",
    "discount_percentage": 0.0,
    "discount_cents": 5000,
    "duration_in_seconds": null,
    "general_notes": "This is a test - csv runner and mult-line item",
    "auto_integrate_repair_order_id": null,
    "fees_cents": 0,
    "sent_to_ai_at": null,
    "is_sample": false,
    "label_list": [
        "Service: GEN"
    ],
    "labor_subtotal": 0.0,
    "parts_subtotal": 0.0,
    "discount": 50.0,
    "tax_1": 5.0,
    "tax_2": 0.0,
    "total_amount": 0.0
}

Please let me know if I understand your suggestion correctly, or if you have any other suggestions. Thank you! - J

Hi @j_who,

I’m glad you tried it out! Looks like what I said worked, in the sense that it pulled the json data out of the csv cell successfully, but doesn’t seem like you got your expected response.

It looks like you did understand my suggestion correctly, and perhaps I didn’t provide enough implementation guidance.

So let me ask this. Exactly how does your request body need to look like, in order to create a proper service entry with multiple service tasks? It seems to me from what you sent (in the link), you only are doing it based on service_task_ids and not a break down of what that service task is.

So if you just want to do this via service_task_ids I would make it an array.

"service_task_ids": [
        543234,
        54325432
    ]

Thats apparently how its supposed to look, according to their documentation. So I would make a cell equal to [ 543234, 54325432]. I am including the brackets as to not mess up the csv file with the comma here to separate those service task ids.

So when you put it in request body, it should look like this:

service_task_ids: "{{service_task_ids}}"

Let me know if this works!

Orest

@odanylewycz perfect, I understand your suggestion. I will give this a try this afternoon and let you know how it goes. Thank you!

Hi @odanylewycz, I’ve spent some time working through different versions of a solution here and unfortunately are still stuck. My tests with the service_task_ids array get a 201 from the API; however, no service task data is written into the software. It’s very strange.

I even created a single POST request w/ the key value pairs typed out in the form-data body. I included an array of actual service_task_id values = [3193541, 3191603] in the request. It was created successfully with all of my form data, but no service_task data was written to the entry.

I’m suspecting something is not accurate w/in the documentation and it’s required the service task is written only after the service_entry is created (as two separate POST calls) despite being listed as a key in the /service_entries request. I reached out to the dev team to confirm this point with a ton of examples from the work we’ve gone through here. I’m waiting to hear back from them and will update this thread w/ what they say either way.

While still thinking about this alternative, the sequence I’m envisioning would be putting a setNextRequest condition w/in a for loop that is iterating over the length of my service_task_ids array. Is this possible in your experience?

  1. POST: Create Service Entry. Parse service_entry_id from the response
    and use postman.setNextRequest(“Create Service Task Line Item”) while also creating and setting a {{variable}} for my service_task_ids array and their descriptions (:man_shrugging: ?)
  2. POST: Create Service Task Line Item with the first service_task_id from the array.
  3. Repeat step #2 for the length of my service_task_ids array in my data file

Sample Data:
Service Entry #1: ref docs

vehicle_id completed_at started_at odometer odometer_void vendor_id label_list reference general_notes custom_fields[account_category] custom_fields[expense_label_temp] custom_fields[repair_order_id] tax_1_type tax_1 discount_type discount total_amount
983951 2020-02-10 0:00:00 59678 FALSE 460408 Service: OICH, 20178775 Validated and updated during Fleetio service data CNVY clean-up Q1-2020. Previous service_entry_id = 6692449 \n PO notes from Donlen network: \n Mileage Services DLN 6692449 fixed $0.00 fixed $0.00 $210.21

3 Service Task Line Items for Service Entry #1: ref docs

service_task_id_list service_task_1 service_task_2 service_task_3 description_list description_1 description_2 description_3 labor_cost_list parts_cost_list labor_cost_1 labor_cost_2 labor_cost_3 parts_cost_1 parts_cost_2 parts_cost_3
3193541;3191603;3194741 3193541 3191603 3194741 Oil Change, Service Subcategory ID = 4;Lubrication, Service Subcategory ID = S59;Tire Services, Service Subcategory ID = S82 Oil Change, Service Subcategory ID = 4 Lubrication, Service Subcategory ID = S59 Tire Services, Service Subcategory ID = S82 10;15;30 20;40;60 $10.00 $15.00 $30.00 $20.00 $40.00 $60.00