5 use FS::Record qw( qsearch qsearchs );
14 FS::API - Freeside backend API
22 This module implements a backend API for advanced back-office integration.
24 In contrast to the self-service API, which authenticates an end-user and offers
25 functionality to that end user, the backend API performs a simple shared-secret
26 authentication and offers full, administrator functionality, enabling
27 integration with other back-office systems.
29 If accessing this API remotely with XML-RPC or JSON-RPC, be careful to block
30 the port by default, only allow access from back-office servers with the same
31 security precations as the Freeside server, and encrypt the communication
32 channel (for example, with an SSH tunnel or VPN) rather than accessing it
41 Adds a new payment to a customers account. Takes a hash reference as parameter with the following keys:
64 Option date for payment
68 my $result = FS::API->insert_payment(
69 'secret' => 'sharingiscaring',
75 '_date' => 1397977200, #UNIX timestamp
78 if ( $result->{'error'} ) {
79 die $result->{'error'};
82 print "paynum ". $result->{'paynum'};
91 my($class, %opt) = @_;
92 my $conf = new FS::Conf;
93 return { 'error' => 'Incorrect shared secret' }
94 unless $opt{secret} eq $conf->config('api_shared_secret');
96 #less "raw" than this? we are the backoffice API, and aren't worried
97 # about version migration ala cust_main/cust_location here
98 my $cust_pay = new FS::cust_pay { %opt };
99 my $error = $cust_pay->insert( 'manual'=>1 );
100 return { 'error' => $error,
101 'paynum' => $cust_pay->paynum,
105 # pass the phone number ( from svc_phone )
106 sub insert_payment_phonenum {
107 my($class, %opt) = @_;
108 my $conf = new FS::Conf;
109 return { 'error' => 'Incorrect shared secret' }
110 unless $opt{secret} eq $conf->config('api_shared_secret');
112 $class->_by_phonenum('insert_payment', %opt);
117 my($class, $method, %opt) = @_;
118 my $conf = new FS::Conf;
119 return { 'error' => 'Incorrect shared secret' }
120 unless $opt{secret} eq $conf->config('api_shared_secret');
122 my $phonenum = delete $opt{'phonenum'};
124 my $svc_phone = qsearchs('svc_phone', { 'phonenum' => $phonenum } )
125 or return { 'error' => 'Unknown phonenum' };
127 my $cust_pkg = $svc_phone->cust_svc->cust_pkg
128 or return { 'error' => 'Unlinked phonenum' };
130 $opt{'custnum'} = $cust_pkg->custnum;
132 $class->$method(%opt);
138 Adds a a credit to a customers account. Takes a hash reference as parameter with the following keys
156 The date the credit will be posted
160 my $result = FS::API->insert_credit(
161 'secret' => 'sharingiscaring',
166 '_date' => 1397977200, #UNIX timestamp
169 if ( $result->{'error'} ) {
170 die $result->{'error'};
173 print "crednum ". $result->{'crednum'};
182 my($class, %opt) = @_;
183 my $conf = new FS::Conf;
184 return { 'error' => 'Incorrect shared secret' }
185 unless $opt{secret} eq $conf->config('api_shared_secret');
187 $opt{'reasonnum'} ||= $conf->config('api_credit_reason');
189 #less "raw" than this? we are the backoffice API, and aren't worried
190 # about version migration ala cust_main/cust_location here
191 my $cust_credit = new FS::cust_credit { %opt };
192 my $error = $cust_credit->insert;
193 return { 'error' => $error,
194 'crednum' => $cust_credit->crednum,
198 # pass the phone number ( from svc_phone )
199 sub insert_credit_phonenum {
200 my($class, %opt) = @_;
201 my $conf = new FS::Conf;
202 return { 'error' => 'Incorrect shared secret' }
203 unless $opt{secret} eq $conf->config('api_shared_secret');
205 $class->_by_phonenum('insert_credit', %opt);
211 Adds a a credit to a customers account. Takes a hash reference as parameter with the following keys: custnum,payby,refund
215 my $result = FS::API->insert_refund(
216 'secret' => 'sharingiscaring',
222 '_date' => 1397977200, #UNIX timestamp
225 if ( $result->{'error'} ) {
226 die $result->{'error'};
229 print "refundnum ". $result->{'crednum'};
236 my($class, %opt) = @_;
237 my $conf = new FS::Conf;
238 return { 'error' => 'Incorrect shared secret' }
239 unless $opt{secret} eq $conf->config('api_shared_secret');
241 # when github pull request #24 is merged,
242 # will have to change over to default reasonnum like credit
243 # but until then, this will do
244 $opt{'reason'} ||= 'API refund';
246 #less "raw" than this? we are the backoffice API, and aren't worried
247 # about version migration ala cust_main/cust_location here
248 my $cust_refund = new FS::cust_refund { %opt };
249 my $error = $cust_refund->insert;
250 return { 'error' => $error,
251 'refundnum' => $cust_refund->refundnum,
255 # pass the phone number ( from svc_phone )
256 sub insert_refund_phonenum {
257 my($class, %opt) = @_;
258 my $conf = new FS::Conf;
259 return { 'error' => 'Incorrect shared secret' }
260 unless $opt{secret} eq $conf->config('api_shared_secret');
262 $class->_by_phonenum('insert_refund', %opt);
268 # "2 way syncing" ? start with non-sync pulling info here, then if necessary
269 # figure out how to trigger something when those things change
271 # long-term: package changes?
275 Creates a new customer. Takes a hash reference as parameter with the following keys:
285 first name (required)
293 (not typically collected; mostly used for ACH transactions)
299 =item address1 (required)
303 =item city (required)
311 =item state (required)
333 Currently used for third party tax vendor lookups
337 Used for determining FCC 477 reporting
341 Used for determining FCC 477 reporting
361 comma-separated list of email addresses for email invoices. The special value 'POST' is used to designate postal invoicing (it may be specified alone or in addition to email addresses),
363 Set to 1 to enable postal invoicing
367 CARD, DCRD, CHEK, DCHK, LECB, BILL, COMP or PREPAY
371 Card number for CARD/DCRD, account_number@aba_number for CHEK/DCHK, prepaid "pin" for PREPAY, purchase order number for BILL
375 Credit card CVV2 number (1.5+ or 1.4.2 with CVV schema patch)
379 Expiration date for CARD/DCRD
383 Exact name on credit card for CARD/DCRD, bank name for CHEK/DCHK
385 =item referral_custnum
387 referring customer number
395 Agent specific customer number
397 =item referral_custnum
399 Referring customer number
404 #certainly false laziness w/ClientAPI::Signup new_customer/new_customer_minimal
405 # but approaching this from a clean start / back-office perspective
406 # i.e. no package/service, no immediate credit card run, etc.
409 my( $class, %opt ) = @_;
411 my $conf = new FS::Conf;
412 return { 'error' => 'Incorrect shared secret' }
413 unless $opt{secret} eq $conf->config('api_shared_secret');
415 #default agentnum like signup_server-default_agentnum?
416 #$opt{agentnum} ||= $conf->config('signup_server-default_agentnum');
418 #same for refnum like signup_server-default_refnum
419 $opt{refnum} ||= $conf->config('signup_server-default_refnum');
421 $class->API_insert( %opt );
428 Returns general customer information. Takes a hash reference as parameter with the following keys: custnum and API secret
433 my( $class, %opt ) = @_;
434 my $conf = new FS::Conf;
435 return { 'error' => 'Incorrect shared secret' }
436 unless $opt{secret} eq $conf->config('api_shared_secret');
438 my $cust_main = qsearchs('cust_main', { 'custnum' => $opt{custnum} })
439 or return { 'error' => 'Unknown custnum' };
441 $cust_main->API_getinfo;
446 Returns location specific information for the customer. Takes a hash reference as parameter with the following keys: custnum,secret
452 #I also monitor for changes to the additional locations that are applied to
453 # packages, and would like for those to be exportable as well. basically the
454 # location data passed with the custnum.
457 my( $class, %opt ) = @_;
458 my $conf = new FS::Conf;
459 return { 'error' => 'Incorrect shared secret' }
460 unless $opt{secret} eq $conf->config('api_shared_secret');
462 my @cust_location = qsearch('cust_location', { 'custnum' => $opt{custnum} });
466 'locations' => [ map $_->hashref, @cust_location ],
472 #Advertising sources?