Endpoints are the terminal step in process of serving a request. (See the docs on filters to see what the intermediate steps might be.) An endpoint can simply be viewed as the logic that is ultimately responsible for generating a response to a particular request. You create an endpoint by annotating a function like so:

#* @get /hello
  return("hello world")

This annotation specifies that this function is responsible for generating the response to any GET request to /hello. (If you’re unfamiliar with GET and POST HTTP requests, you can read up on them here.) Typically, the value returned from the function will be used as the response to the request (after being serialized through a serializer to e.g. convert the response into JSON). In this case, a GET response to /hello would return the content ["hello world"] with a JSON content-type, unless you’ve changed the serializer type.

HTTP Methods

Endpoints can be specified for any of the four major HTTP “verbs”: GET, POST, PUT, and DELETE using the annotations @get, @post, @put, and @delete, respectively. As you might expect, a function annotated with @get will respond only to GET requests. So if you intend an endpoint to be accessed via multiple HTTP methods, you would need to annotate them with each relevant method as in:

#* @get /vehicle
#* @put /vehicle
#* @post /vehicle

Error Handling

If an endpoint generates an error, the error handler will generate a response on behalf of the endpoint. By default, this involves capturing the error message and returning a serialized response with an HTTP status code of 500 to signify a server error.


Below on the left you’ll find a web application that uses jQuery to send requests to a plumber API which processes those requests. You can edit the slider inputs to preview what the request would look like before submitting it to the API. The code for the plumber API is included on the right so you can see how each endpoint would behave.

The plumber server is hosted at https://plumber.tres.tl/append/.

POST /append

Click "Post" to see the response.

GET /tail

Click "Get" to see the response.

GET /graph

GET https://plumber.tres.tlappend/graph


        # The list of values, start with the number 15
values <- 15

# The maximum number of values to store in our list
MAX_VALS <- 50

#* Append to our values
#* @post /append
function(val, res){
  v <- as.numeric(val)
  if (is.na(v)){
    res$status <- 400
    res$body <- "val parameter must be a number"
  values <<- c(values, val)

  if (length(values) > MAX_VALS){
    values <<- tail(values, n=MAX_VALS)


#* Get the last few values
#* @get /tail
function(n="10", res){
  n <- as.numeric(n)
  if (is.na(n) || n < 1 || n > MAX_VALS){
    res$status <- 400
    res$body <- "parameter 'n' must be a number between 1 and 100"

  list(val=tail(values, n=n))

#* Get a graph of the values
#* @png
#* @get /graph
  plot(values, type="b", ylim=c(1,100), main="Recent Values")