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
399 Agent specific customer number
401 =item referral_custnum
403 Referring customer number
408 #certainly false laziness w/ClientAPI::Signup new_customer/new_customer_minimal
409 # but approaching this from a clean start / back-office perspective
410 # i.e. no package/service, no immediate credit card run, etc.
413 my( $class, %opt ) = @_;
415 my $conf = new FS::Conf;
416 return { 'error' => 'Incorrect shared secret' }
417 unless $opt{secret} eq $conf->config('api_shared_secret');
419 #default agentnum like signup_server-default_agentnum?
420 #$opt{agentnum} ||= $conf->config('signup_server-default_agentnum');
422 #same for refnum like signup_server-default_refnum
423 $opt{refnum} ||= $conf->config('signup_server-default_refnum');
425 $class->API_insert( %opt );
432 Returns general customer information. Takes a hash reference as parameter with the following keys: custnum and API secret
437 my( $class, %opt ) = @_;
438 my $conf = new FS::Conf;
439 return { 'error' => 'Incorrect shared secret' }
440 unless $opt{secret} eq $conf->config('api_shared_secret');
442 my $cust_main = qsearchs('cust_main', { 'custnum' => $opt{custnum} })
443 or return { 'error' => 'Unknown custnum' };
445 $cust_main->API_getinfo;
450 Returns location specific information for the customer. Takes a hash reference as parameter with the following keys: custnum,secret
456 #I also monitor for changes to the additional locations that are applied to
457 # packages, and would like for those to be exportable as well. basically the
458 # location data passed with the custnum.
461 my( $class, %opt ) = @_;
462 my $conf = new FS::Conf;
463 return { 'error' => 'Incorrect shared secret' }
464 unless $opt{secret} eq $conf->config('api_shared_secret');
466 my @cust_location = qsearch('cust_location', { 'custnum' => $opt{custnum} });
470 'locations' => [ map $_->hashref, @cust_location ],
476 #Advertising sources?