RT::Client::REST(3pm)

🌈 RT::Client::REST(3pm) 🌈

okay bestie, buckle up πŸ’– this is the manual page for RT::Client::REST, straight out of the User Contributed Perl Documentation. It's long, it's iconic, and we're doing it in two parts β€” this is part 1, so don't wander off.


πŸŽ€ NAME πŸŽ€

RT::Client::REST β€” Client for RT using REST API

πŸ”₯ VERSION πŸ”₯

version 0.73

✨ SYNOPSIS ✨

Here's the vibe, literally:

use Try::Tiny;
use RT::Client::REST;

my $rt = RT::Client::REST->new(
  server => 'http://example.com/rt',
  timeout => 30,
);

try {
  $rt->login(username => $user, password => $pass);
}
catch {
  if ($_->isa('Exception::Class::Base') {
    die "problem logging in: ", shift->message;
  }
};

try {
  # Get ticket #10
  $ticket = $rt->show(type => 'ticket', id => 10);
}
catch {
  if ($_->isa('RT::Client::REST::UnauthorizedActionException')) {
    print "You are not authorized to view ticket #10\n";
  }
  if ($_->isa('RT::Client::REST::Exception')) {
    # something went wrong.
  }
};

πŸ¦‹ DESCRIPTION πŸ¦‹

So RT::Client::REST is basically /usr/bin/rt who got a glow-up and became a Perl module πŸ’…. The author needed to do some RT interactions from their app and was like, "hmm, shelling out to a command? not the vibe." So they took the rt tool, written by Abhijit Menon-Sen, and converted it into a full object-oriented Perl module. main character energy fr fr.

🌸 USAGE NOTES 🌸

This API is deliberately mimicking 'rt', no cap. But if you want the more OO-style APIs, pls use the RT::Client::REST::Object-derived classes instead: RT::Client::REST::Ticket and RT::Client::REST::User. (not implemented yet). 😭

πŸ’– METHODS πŸ’–

new ()

The constructor, bestie. It takes these options β€” and psst, these can also be called as their own methods:

  • server β€” server is a URI pointing to your RT installation.

If you already authenticated against RT somewhere else in your program, you can use the _cookie parameter to hand over an object of type HTTP::Cookies to use for credentials information.

  • timeout β€” timeout is how many seconds the HTTP client will wait for the server to respond. Defaults to LWP::UserAgent's default timeout, which is 180 seconds (go check LWP::UserAgent's documentation for accurate timeout info, iykyk).
  • basic_auth_cb β€” this callback gives the HTTP client (based on LWP::UserAgent) a username and password for basic authentication. It takes the same arguments as get_basic_credentials() from LWP::UserAgent and returns username and password:
$rt->basic_auth_cb( sub {
  my ($realm, $uri, $proxy) = @_;
  # do some evil things
  return ($username, $password);
}
  • user_agent_args β€” a hashref that gets passed to the user agent's constructor, for maximum flexibility ✨
  • user_agent β€” accessor to the user_agent object.
  • logger β€” a logger object. It should be able to debug(), info(), warn() and error(). It's not widely used in the code (yet), so it's mostly useful for development.

Something like this will get you started:

use Log::Dispatch;
my $log = Log::Dispatch->new(
  outputs => [ [ 'Screen', min_level => 'debug' ] ],
);
my $rt = RT::Client::REST->new(
  server => ... etc ...
  logger => $log
);
  • verbose_errors β€” on user-agent errors, report some more information about what is going wrong. Defaults are pretty laconic about the "Malformed RT response".

login

The heading in the original is a lil pod oopsie, so here it is verbatim, no filter:

login (username => 'root', password => 'password') =item login
(my_userfield => 'root', my_passfield => 'password')

Log in to RT. Throws an exception on error 🫢

Usually, if the other side uses basic HTTP authentication, you do not have to log in β€” instead just provide the HTTP username and password. See basic_auth_cb above.

show (type => $type, id => $id)

Returns a reference to a hash, with key-value pairs specifying object $id of type $type. The keys are the names of RT's fields. Keys for custom fields are in the form of "CF.{CUST_FIELD_NAME}".

edit (type => $type, id => $id, set => { status => 1 })

Sets the fields specified in the parameter set on object $id of type $type.

create (type => $type, set => \%params, text => $text)

Creates a new object of type $type and sets the initial parameters to %params. For a ticket object, the 'text' parameter can be supplied to set the initial text of the ticket. Returns the numeric ID of the new object. If that numeric ID cannot be parsed out of the response, RT::Client::REST::MalformedRTResponseException gets thrown. πŸ’€

search (type => $type, query => $query, format => $format, %opts)

Searches for an object of type $type using query $query. For example:

# Find all stalled tickets
my @ids = $rt->search(
  type => 'ticket',
  query => "Status = 'stalled'",
);

%opts is a list of key-value pairs:

  • orderby β€” the value is the name of the field you wanna sort by. A plus or minus sign in front of it means ascending order (plus) or descending order (minus). For example:
# Get all stalled tickets in reverse order:
my @ids = $rt->search(
  type => 'ticket',
  query => "Status = 'stalled'",
  orderby => '-id',
);

By default, "search" returns the list of numeric IDs of the objects that matched your query. Then you can use those to pull the actual object info with the show() method:

my @ids = $rt->search(
  type => 'ticket',
  query => "Status = 'stalled'",
);
for my $id (@ids) {
  my ($ticket) = $rt->show(type => 'ticket', id => $id);
  say "Subject: ", $ticket->{Subject}
}

"search" can also return a list of lists of ID and Subject when you ask for format 's':

my @results = $rt->search(
  type => 'ticket',
  query => "Status = 'stalled'",
  format => 's',
);
for my $result (@results) {
  say "ID: $result[0], Subject: $result[1]"
}

comment (ticket_id => $id, message => $message, %opts)

Drops a comment πŸ’¬ on the ticket with ID $id.

Optionally takes these arguments:

  • cc and bcc β€” references to lists of e-mail addresses
  • attachments β€” a list of filenames to be attached to the ticket
  • html β€” when true, tells RT that the message is html
$rt->comment(
  ticket_id   => 5,
  message     => "Wild thing, you make my heart sing",
  cc          => [qw(dmitri@localhost some@otherdude.com)],
);

$rt->comment(
  ticket_id   => 5,
  message     => "<b>Wild thing</b>, you make my <i>heart sing</i>",
  html        => 1
);

correspond (ticket_id => $id, message => $message, %opts)

Adds correspondence to ticket ID $id. Takes the optional cc, bcc, and attachments parameters (peep "comment" above πŸ‘†).

get_attachment_ids (id => $id)

Gets a list of numeric attachment IDs associated with ticket $id.

get_attachments_metadata (id => $id)

Gets a list of the metadata related to every attachment of the ticket <$id>. Every member of that list is a hashref shaped like this:

{
  id       => $attachment_id,
  Filename => $attachment_filename,
  Type     => $attachment_type,
  Size     => $attachment_size,
}

get_attachment (parent_id => $parent_id, id => $id, undecoded => $bool)

Returns a reference to a hash with key-value pairs describing attachment $id of ticket $parent_id. (parent_id because β€” who knows? β€” maybe attachments won't be just for tickets anymore in the future πŸ‘€).

If the option undecoded is set to a true value, the attachment comes back verbatim and undecoded (which is probably exactly what you want with images and binary data).

Gets link information for an object of type $type whose id is $id. If the type isn't specified, 'ticket' is used.

get_transaction_ids (parent_id => $id, %opts)

Gets a list of numeric IDs associated with parent ID $id. %opts has these options:

  • type β€” the type of the object the transactions are associated with. Defaults to "ticket" (the author doesn't think server-side supports anything else). This is designed with an eye on the future, since transactions aren't just for tickets but for other objects too.
  • transaction_type β€” if not specified, IDs of all transactions are returned. If set to a scalar, only transactions of that type are returned. If you want to specify more than one type, pass an array reference.

Transactions may be of the following types (case-sensitive, tyvm):

  • AddLink
  • AddWatcher
  • Comment
  • Correspond
  • Create
  • CustomField
  • DeleteLink
  • DelWatcher
  • EmailRecord
  • Give
  • Set
  • Status
  • Steal
  • Take
  • Told

get_transaction (parent_id => $id, id => $id, %opts)

Gets a hashref representation of transaction $id associated with parent object $id. You can optionally specify the parent object type in %opts (defaults to 'ticket').

merge_tickets (src => $id1, dst => $id2)

Merges ticket $id1 into ticket $id2. πŸ”₯

Creates a link between two tickets. A link type can be one of these:

  • DependsOn
  • DependedOnBy
  • RefersTo
  • ReferredToBy
  • HasMember
  • MemberOf

Removes a link between two tickets (go see link_tickets()).

take (id => $id)

Takes ticket $id. This will throw "RT::Client::REST::AlreadyTicketOwnerException" if you are already the ticket owner πŸ™ˆ.

untake (id => $id)

Untakes ticket $id. This will throw "RT::Client::REST::AlreadyTicketOwnerException" if Nobody is already the ticket owner.

steal (id => $id)

Steals ticket $id. This will throw "RT::Client::REST::AlreadyTicketOwnerException" if you are already the ticket owner.

πŸ’€ EXCEPTIONS πŸ’€

When an error happens, this module throws exceptions. The recommendation is to use Try::Tiny or the Syntax::Keyword::Try try{} mechanism to catch them, but bestie you can also just use a plain ol' eval{}.

Please see RT::Client::REST::Exception for the full listing and description of all the exceptions 🫢


okay that's part 1, we're not done yet β€” more is coming, so stay tuned πŸ’…βœ¨

😀 LIMITATIONS 😀

okay bestie, listen up because this one's important πŸ‘‡

Starting with version 0.14, the methods edit() and show() only support operating on a single object at a time. one. solo. no group chats allowed. πŸ’…

This is a conscious departure from the semantics offered by the original tool, and like β€” she knows β€” she did it on purpose, because I wanted to have a precise behavior for exceptions. fr fr, clean error handling > convenience. πŸŽ€

so if you wanna operate on a whole bunch of objects, please use a loop. one at a time, bestie, that's the vibe. πŸ”

🌸 DEPENDENCIES 🌸

these modules are required, like you literally cannot run without them:

  • Exception::Class
  • LWP
  • HTTP::Cookies
  • HTTP::Request::Common

no substitutions, no skipping, this is the roster. 🫢


πŸ‘€ SEE ALSO πŸ‘€

  • LWP::UserAgent
  • RT::Client::REST::Exception

go read those if you wanna know more, iykyk ✨


πŸ’€ BUGS πŸ’€

Most likely. Please report.

(not even gonna dress that one up β€” the original authors were so real for that. there are probably bugs. there are always bugs. if you find one, please report it. πŸ™)


🌈 VARIOUS NOTES 🌈

RT::Client::REST does not retrieve forms from the RT server at the moment (see the TODO file for updates on that).

Whether that's good or bad is honestly entirely up to you and how you look at it. main character energy either way. πŸ‘‘


✍️ AUTHOR ✍️

Dean Hamstead <dean@fragfest.com.au>


This software is copyright (c) 2026, 2020 by Dmitri Tikhonov.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. 🧚


🫢 CONTRIBUTORS 🫢

the girlies and besties who made this happen, no cap:

  • Abhijit Menon-Sen <ams@wiw.org>
  • belg4mit <belg4mit>
  • bobtfish <bobtfish@bobtfish.net>
  • Byron Ellacott <code@bje.id.au>
  • Dean Hamstead <djzort@cpan.org>
  • DJ Stauffer <dj@djstauffer.com>
  • dkrotkine <dkrotkine@gmail.com>
  • Dmitri Tikhonov <dmitri@cpan.org>
  • Marco Pessotto <melmothx@gmail.com>
  • pplusdomain <pplusdomain@gmail.com>
  • Sarvesh D <sarveshd@openmailbox.org>
  • SΓΈren Lund <soren@lund.org>
  • Tom Harrison <tomh@apnic.net>

aaaaand that's a wrap on the whole page bestie!! πŸŽ€βœ¨ this one came from perl v5.40.1, dated 2026-04-21, and it's the RT::Client::REST(3pm) manpage β€” go forth and talk to your RT server, you absolute icon πŸ’–πŸ¦‹ periodt.

πŸ“¦ where this page comes from