RepairShopr REST API - Build custom extensions/apps/addons

RepairShopr API Documentation

RepairShopr uses a very simple HTTP REST API.

Here is a little light reading material that might help get you up to speed quickly;


Our API has a very simple authorization, a user-level API key passed as a param.

You can go get your API key on your profile page;

There you go:

Obtaining a new key

Just click that little 'reset' link on the profile page and a new key will be generated. It will immediately block access to the current/old key.

Rate Limits

This is subject to change but currently we'll allow 120 requests per minute for each account before responding with an error.

Request Format

We return all data as json. When sending data in to us you can use regular form encoding or set the content type to json and use it in the body.

You can send a simple HTTP GET to many endpoints, just pass the api_key parameter like so;

Please note that all requests must be HTTPS as opposed to HTTP.


All the endpoints are paginating. You can add a param like &page=2 to the request to get to the other pages. Here are the defaults;
  • Customers: 100
  • Invoices: 50
  • Leads: 20
  • Tickets: 100


We are exposing endpoints as-needed, there are a handful that have been in production for a while now. Here you go!

User /api/v1

  • me GET /me
    A helper endpoint to show you who is logged in and state their permissions. It returns something like this:
  • login POST /sign_in
    returns the same user object from above
    valid params: :email, :password

Leads /api/v1

  • index GET /leads.json
  • show GET /leads/:id
  • new GET /leads/new (instructions)
  • create POST /leads
For some extra things you can do with leads, including using PHP, please click here!

Valid parameters
:first_name, :last_name, :email, :phone, :mobile, :created_at, :updated_at,
:address, :city, :state, :zip, :ticket_subject, :ticket_description,
:ticket_problem_type, :ticket_id, :customer_id, :contact_id, :properties, :file_url

You can set "Custom Fields" using as hash/object/dict in the properties field. These will map over to the ticket custom fields when you convert it. Here is an example curl setting it via json:
curl -v -H "Accept: application/json" -H "Content-type: application/json" -X POST -d ' {"first_name":"John","last_name":"Smith","properties":{"device":"Apple"}}'

Customers /api/v1

  • index GET /customers
    Also supports search, pass a parameter named "query" to do a search
  • show GET /customers/:id
  • create POST /customers
  • update PUT /customers/:id
  • autocomplete GET /customers/autocomplete (with param query=STRING)
Valid parameters
:business_name, :firstname, :lastname, :email, :phone, :mobile, :address, :address_2, :city, :state, :zip, :notes, :get_sms, :opt_out, :no_email, :ref_customer_id, :referred_by, :properties, :disabled, :tax_rate_id, :notification_email, :invoice_cc_emails, :invoice_term_id
GDPR feature users can also set :consent parameter, :consent is a hash with three possible keys: :store_data, :notice_emails, :marketing. The values are '1' for yes and '0' for no.
For example "consent: {store_data: '1', marketing: '0'}" means customer agrees to store data and opt out marketing emails. Here is an example curl:
 curl -X POST  \
 -H "Content-Type: application/json"   \
 -d '{
"api_key": "d70a0c3c-8c0e-44fb-8a25-e2e5af5faabe",
"firstname": "Bob",
"lastname": "Smith",
"email": "",
 "phone": "123456789",
"consent": {"store_data": "1", "marketing": "0"}

  • include_disabled
  • query
  • sort (looks like "id desc" or "updated_at desc")
  • firstname, lastname, business_name
  • id and id_not accept both a single id or an array of ids

Customers Phones Association /api/v1

  • index GET /customers/:id/phones
  • update PUT /customers/:id/phones/:phone_id
  • create POST /customers/:id/phones
Valid parameters
:label, :number, :extension

Contacts /api/v1

  • index GET /contacts.json?customer_id=123
  • show GET /contacts/123
  • create POST /contacts
  • update PUT /contacts/123
Valid Parameters
:customer_id, :name, :address1, :address2, :city, :state, :zip, :email,
                 :phone, :mobile, :notes

Example curl: 

curl --data "api_key=YOUR_API_KEY&customer_id=3411&name=Steve Jobs"

Invoices /api/v1

  • index GET /invoices
  • For GET we have some filters too: unpaid, paid, ticket_id, since_updated_at. You can pass a date into since_updated_at like "2017-01-01" or even a date+time "2017-01-01 14:00". unpaid/paid are just boolean
  • create POST /invoices

Valid parameters
:number, :date, :customer_id, :employee, :date_received,
:ticket_id, :took_payment, :paid, :location_id
:line_items [
 item, name, quantity, cost, price, taxable

Invoices Line Items /api/v1/invoices/:id/
 - create POST /invoices/:id/line_items
 - update PUT /invoices/:id/line_items/:line_item_id
 - delete DELETE /invoices/:id/line_items/:line_item_id

(Item and Name are known as item and description in the app)

Valid Params for Create: product_id, quantity, item, name, discount_dollars, line_discount_percent
Valid Params for Update: item, name - to change quantity or product, you must delete and create a new line item

Example curl to create an invoice with a line item:
curl -v -H "Accept: application/json" -H "Content-type: application/json" -X POST -d ' {"customer_id":"4972350","line_items":[{"item":"Test","product_id":"39","name":"Test","quantity":"2","cost":"10","price":"94.99","line_discount_percent":50}]}'

Example curl adding a discounted line item:
curl -v -H "Accept: application/json" -H "Content-type: application/json" -X POST -d ' {"product_id":"39","quantity":"2","line_discount_percent":50}'

Example curl updating the pricing on a line item:
curl -v -H "Accept: application/json" -H "Content-type: application/json" -X PUT -d ' {"cost":"10","price":"999.99"}' https://subdomain/api/v1/invoices/2792178/line_items/5286500?api_key=YOUR_API_KEY

Example curl creating a manual line item with pricing:
curl -v -H "Accept: application/json" -H "Content-type: application/json" -X POST -d ' {"item":"Test","name":"Test","quantity":"2","cost":"10","price":"94.99"}' https://subdomain/api/v1/invoices/2792178/line_items?api_key=YOUR_API_KEY

Reccurring Invoices /api/v1

Please note that Recurring Invoices model and endpoint is named Schedule.

  • index GET /schedules
  • create POST /schedules
  • update PUT /schedules/:id
  • add line POST /schedules/:id/add_line_item
  • update line PUT /schedules/:id/update_line_item
  • remove line POST /schedules/:id/remove_line_item
Valid Schedule parameters
:customer_id - integer - recurring invoice customer id
:email_customer - boolean - email customer on invoice creation?
:frequency - string - recurring invoice frequency, valid values are "Daily", "Monthly", "Weekly", "Biweekly", 'Quarterly', 'Semi-Annually', "Annually", "Biennially", "Triennially"
:name - string - recurring invoice name
:next_run - date - next run date, it is automatically updated on recurring invoice run
:snail_mail - boolean - send physical mail to the customer on recurring invoice run
:charge_mop - boolean - charge customer saved payment profile on recurring invoice run
:invoice_unbilled_ticket_charges - boolean - add any unbilled customer's ticket charges to the invoice on recurring invoice run
:paused - boolean - pause the recurring invoice

Valid Schedule Line Item parameters
:cost_cents - integer - line item cost in cents
:retail_cents - integer - line item retail price in cents
:description - string - line item description
:name - string - line item name
:position - integer - line item position, it is used to sort the line items
:product_id - integer - product id
:taxable - boolean - is this line item taxable
:user_id - integer - id of the user who created the line item, this data is used to generate various reports
:asset_type_id - bill customers for assets of sertain asset type, :recurring_type_id should be set to 4 to make this feature work
:recurring_type_id - integer - There are types of recurring line items with different behavior
1 is default line item
4 is Asset Counter, it will automatically update the line item quantity based on count of customer's assets of :asset_type_id
5 is RMM Package, it will automatically update the line item quantity based on line item's product RMM Policy association
:quantity - integer - can be updated automatically depending on :recurring_type_id
:one_time_charge - boolean - remove the line item after next run

  • customer_id


 List Recurring Invoices
curl -X GET

 Create a Recurring Invoice
curl -X POST --data "api_key=YOUR_API_KEY&customer_id=5&name=Subscription&frequency=Daily&next_run=2018-10-1"

 Add a Line Item to a Recurring Invoice
curl -X POST --data "api_key=YOUR_API_KEY&schedule_line_item[product_id]=4&schedule_line_item[quantity]=5"

 Update a Line Item
curl -X PUT --data "api_key=YOUR_API_KEY&schedule_line_item_id=12&schedule_line_item[retail_cents]=10000"

 Remove a Line Item
curl -X POST --data "api_key=147ade99-c778-41ef-978c-120c578fad8d&schedule_line_item_id=12"

Payment Methods /api/v1

  • index GET /payment_methods
Read-Only - just to allow some integrations, our mobile app, etc

Tickets /api/v1

  • index GET /tickets (optional; customer_id, number, status=Not Closed, resolved_after=2017-01-10, since_updated_at=2017-01-01, term=subject_query_here, mine=true, ticket_search_id=123)
  • show GET /tickets/:id
  • new GET /tickets/new (instructions)
  • create POST /tickets
  • update PUT /tickets/:id
  • add comment POST /tickets/(:number or :id)/comment
  • add timer entry POST /tickets/:id/timer_entry - params: start_at, end_at OR duration_minutes, user_id(optional), notes(optional), product_id(optional), charge_time(true/false)(optional)
  • update timer entry PUT /tickets/:id/update_timer_entry with timer_entry_id and :notes,:start_time,:end_time
  • delete timer entry DELETE /tickets/:id/delete_timer_entry with timer_entry_id
  • attach file POST /tickets/:id/attach_file_url - params: needs an array named 'files' like : [{url: "", filename: 'optional-name.jpg}]
Valid parameters
ticket: :number, :subject, :created_at, :customer_id, :due_date,
:location_id, :problem_type, :status, :user_id, :asset_ids, :properties, :ticket_type_id

If you want to create the initial comment at the same time you can send the comment in a simpler way by using these attributes:

comment_body, comment_subject, comment_tech, comment_do_not_email, comment_hidden, comment_sms_body

Example curl 

curl --data "api_key=YOUR_API_KEY&customer_id=3411&subject=testing&problem_type=Virus&status=New&comment_body=just_testing&comment_subject=Initial Issue"


Body: The message body
Tech: a friendly name to show in the tech field
Do Not Email: boolean, send a "1" or "0" for if we should email the customer or not
Hidden: send a "1" or "0" for if this is a private comment
SMS Body: the body to get sent to customer via SMS

Sample CURL

curl --data "api_key=YOUR_API_KEY&customer_id=3411&subject=testing&problem_type=Virus&status=New&comment_subject=Update&comment_body=I am the body"

Ticket Charges api/v1

  • index GET tickets/:id (tons of detail is in the ticket detail endpoint here)
  • create POST tickets/:id/add_line_item
  • update PUT tickets/:id/update_line_item (ticket_line_item_id=)
  • delete DELETE tickets/:id/remove_line_item (ticket_line_item_id=:id)
Parameters: :name, :product_id, :description, :quantity, :price_cost, :price_retail, :taxable

Ticket Worksheets api/v1

  • coming soon

Ticket Attachments api/v1

  • create POST tickets/:id/attach_file_url
Parameters: :url - send a public URL to a file and we'll download it and attach it

Products /api/v1

  • index GET /products
    Also supports search, pass a param named "sku" to search for a SKU, or pass a param named "query" to do a text search
  • category filter /products?category_id=123
  • show GET /products/:id
  • new GET /products/new (instructions)
  • create POST /products
  • update PUT /products/:id
  • update LocationQuantity (big chain inventory levels) PUT /products/:id/location_quantities (needs location_quantity_id & quantity params)

Valid Parameters:

product: :price_cost, :price_retail, :condition, :description, :maintain_stock,
:name, :quantity, :warranty, :sort_order, :reorder_at, :disabled, :taxable,
:product_category, :upc_code, :discount_percent, :warranty_template_id, :qb_item_id,
:vendor_id, :desired_stock_level, :price_wholesale, :notes, :tax_rate_id,
:physical_location, :serialized
  • name
  • sku
  • id and id_not
  • upc_code
  • sort (looks like "id desc" or "updated_at desc")

Product Photos 

You can now add photos to Products.
POST /api/v1/products/123/add_images
with params like: :url, :filename

You can also remove them:
DELETE /api/v1/products/123/delete_image?photo_id=123

Product Serials ("Instances") /api/v1/products/:123/product_serials

  • We added GET api/v1/products/:product_id/products_serials endpoint.
  • you can filter product serials by status: reserved, sold, returned, used_in_refurb, in_transfer, breakage, default is in_stock
  • update product serials via API PUT api/v1/products/:product_id/products_serials/:id endpoint.
  • create new product serials via API POST api/v1/products/:product_id/products_serials
  • supported params: condition, price_cost_cents, price_retail_cents, serial_number, notes
curl -X PUT '`product_id`/product_serials/`id`?api_key=`api_kley`&serial_number=NEW_SERIAL_NUMBER'
-curl -X GET '`product_id`/product_serials?api_key=`api_key`&status=in_stock'

Appointments /api/v1

  • index GET /appointments
    Optional param named "mine" will filter to the current user
  • show GET /appointments/:id
  • create POST /appointments
  • update PUT /appointments/:id
  • delete DELETE /appointments/:id
Index (list) parameters:
You can use these optional parameters: date_to, date_from, mine

Parameters for Appointments:
If you send an optional ticket_id, the appointment will attach to the ticket instead of just the account.

If you send just a start_at, and appointment_duration param - the appointment_duration looks like this: "6 hours"

You can also send a start_at and end_at, in typical computer formatting like: 2016-03-29 15:00 -0900

The "Owner" of the appointment is the user_id. Attendees are an array of user_ids.
:description, :user_ids, :do_not_email, :user_id,
:end_at, :location, :start_at, :summary, :email_customer,
:appointment_duration, :appointment_type, :appointment_type_id

Assets /api/v1

  • index GET /customer_assets
    customer_id - filters by a customer_id
    asset_type_id - filters by asset_type
    query - does a text search
  • show GET /customer_assets/:id
  • create POST /customer_assets
  • update PUT /customer_assets/:id

Valid parameters:
:name, :customer_id,
:asset_serial, :asset_type_id

Payments /api/v1

  • index GET /payments
  • show GET /payments/:id
  • create POST /payments
  • update PUT /payments/:id

Valid parameters
:invoice_id, :customer_id, :invoice_number, :amount_cents, :first_name, :last_name, :address_street, :address_city, :address_zip, :ref_num, :register_id, :payment_method, :signature_name, :signature_data

Employee Time Logs /api/v1

GET all timelogs for a user

curl -X GET ''

GET last timelog for user #2

curl -X GET ''

CREATE or UPDATE the last timelog(just as we do on web) available params are :lunch, :in_at, :out_at, :in_note, :out_note

in_at and out_at should be in the account's timezone

curl -X PUT ''

- the API key needs 'manage-timelogs' permission to edit other users' timelogs

Feedback and Knowledge Base