Introduction
Documentation
Code samples of these libraries will be shown on this pane. Feel free to choose your
preferred language for samples by selecting it in the top bar of this pane. API endpoint:https://api.processout.com
Welcome to the ProcessOut documentation!
Language bindings and examples for different libraries can be found on the right side of the page. You can switch to your preferred language using the menu at the top of the right side pane.
Get started
Libraries
# No setup needed to use cURL
npm install processout
pip install processout
gem install processout
composer require processout/processout-php
go get gopkg.in/processout.v4
// The godoc can be found at https://godoc.org/gopkg.in/processout.v4
Installing and setting up the libraries/modules/packages in your project is most of the time really easy, and only consists of running a couple of commands and/or dropping in some files.
Please refer to the code on the right to install the library in your preferred language.
You may also want to simply run a git clone
command or download an archive containg
the library, and manage the dependencies yourself.
You can find all our repositories on the ProcessOut Github.
Setting up
var ProcessOut = require("processout");
var client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
To use ProcessOut’s API, you will need to authenticate yourself using your API keys.
Your API keys are composed of your project-id
and project-secret
. To get
these keys, you will need to have created a project on your dashboard.
Once the authentication is done, a ProcessOut
object should be returned,
representing your ProcessOut project.
Expanding resources
curl -X GET -G https://api.processout.com/customers/cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB \
--data-urlencode expand[]=subscriptions
var ProcessOut = require("processout");
var client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
client.newCustomer().find("cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb", {
expand: ["subscriptions"]
}).then(
function(customer) {
// Customer was fetched
}, function(err) {
// An error occured
});
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
customer = client.new_customer().find("cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb", {
"expand": ["subscriptions"]
})
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
customer = client.customer.find("cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb", {
expand: ["subscriptions"]
})
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
$customer = $client->newCustomer()->find("cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb", array(
"expand" => array("subscriptions")
));
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
cust, err := client.NewCustomer().Find("cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb",
processout.CustomerFindParameters{
Options: &processout.Options{
Expand: []string{"subscriptions"},
}),
}
Often, resources fetched through the API will not expand their sub resources by default (such
as a transactions’s customer). This behaviour can be overridden using the expand option.
For example, expanding the Transaction’s Customer can be done by setting expand
to customer
.
It is also possible to expand nested sub resources by using the dot notation.
To expand the Subscriptions of a Customer in a Transaction, you can set
expand
to customer.subscriptions
. This will expand the transaction’s customer,
and then the customer’s subscriptions.
Because expand
is an array, multiple expansions can be done at once. Simply
append all the expansions to be done in the array.
Pagination
curl -X GET -G https://api.processout.com/customers \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB \
--data-urlencode start_after=cust_FM5ZDn3PjkCmDVXYnqrZFrnlypilDicD \
--data-urlencode limit=20 \
--data-urlencode order=asc
var ProcessOut = require("processout");
var client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
client.newCustomer().all({
startAfter: "cust_FM5ZDn3PjkCmDVXYnqrZFrnlypilDicD",
limit: 20,
order: "asc"
}).then(function(customers) {
// Customers were fetched
}, function(err) {
// An error occured
});
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
customers = client.new_customer().all({
"start_after": "cust_FM5ZDn3PjkCmDVXYnqrZFrnlypilDicD",
"limit": 20,
"order": "asc"
})
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
customers = client.customer.all(
start_after: "cust_FM5ZDn3PjkCmDVXYnqrZFrnlypilDicD",
limit: 20,
order: "asc"
)
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
$customers = $client->newCustomer()->all(array(
"startAfter" => "cust_FM5ZDn3PjkCmDVXYnqrZFrnlypilDicD",
"limit" => 20,
"order" => "asc"
));
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
customers, err := client.NewCustomer().All(processout.CustomerAllParameters{
Options: &processout.Options{
StartAfter: "cust_FM5ZDn3PjkCmDVXYnqrZFrnlypilDicD",
Limit: 20,
Order: "asc",
},
})
ProcessOut uses cursor-based pagination. Instead of specifying the page you want to fetch, you instead specify the resource ID from which you want to start fetching. Although this prevents you from randomly accessing items, this makes sure that the results you fetch are consistent and not duplicated. More about it can be found here.
Most of the listable resources on ProcessOut (Customers,
Transactions, Subscriptions for example) can
be paginated. Pagination is done using 4 attributes: start_after
,
end_before
, limit
and order
. You can only specify either start_after
or
end_before
at a time. The cursor (i.e. the item used to paginate) is always
omitted from the results. limit
defaults to 10
and may only be a positive
integer with a maximum value of 100
. order
can be either asc
or desc
, and
defaults to desc
.
Testing
# Simply prepend test- to the project ID and use your sandbox private key
curl -X GET https://api.processout.com/ \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB
var ProcessOut = require("processout");
var client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
// Prefix project ID with `test-`
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
# Prefix project ID with `test-`
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
# Prefix project ID with `test-`
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
// Prefix project ID with `test-`
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
// Prefix project ID with `test-`
It is useful to be able to go through the whole payment process without involving any real payment while implementing ProcessOut.
The ProcessOut testing environment lets you interact with the ProcessOut API without having to go through the checkout processes on the different available gateways. This is especially useful when first implementing payments to your online website.
The testing and production environments are kept entirely separated. Resources created under the test environment may not be accessed in production, and production resources may not be used for test purposes.
Test cards
The checkout flow you’ll experience when implementing ProcessOut will be the exact same as you’d get in production, except no real payment will be made.
In order to properly test edge cases, we provide you with test cards that can be used within ProcessOut.js when tokenizing a card.
Each of those cards have a different behaviour so you can test different scenarios. Any other card will fail.
The full test cards list can be found here ↗.
Error handling
# Error handling with curl should be handled by checking the status
# codes of the responses. Non 2xx response codes usually mean an error
# occured during the request
// Promises should be used to check for any error
// and/or success of the request.
// Let's assume invoice has already been instantiated
invoice.save().then(
function(invoice) {
// Here, the request was successful, and invoice
// has been filled with the response's data. You
// may continue your work here, safe.
}, function(err) {
// An error occured during the request. You may
// check the error message in err.
console.log(err);
});
from processout.errors.authenticationerror import AuthenticationError
from processout.errors.notfounderror import NotFoundError
from processout.errors.validationerror import ValidationError
from processout.errors.genericerror import GenericError
from processout.errors.internalerror import InternalError
# Different type of exceptions may be thrown by the
# ProcessOut's Python library, depending on the situation.
try:
# Some ProcessOut related code
pass
except AuthenticationError as e:
print("Your API credentials couldn't be verified. " + str(e))
except NotFoundError as e:
print("The requested resource could not be found. " + str(e))
except ValidationError as e:
print("This error describes a validation error. " + str(e))
except GenericError as e:
print("This is an error that didn't match any of the above. " + str(e))
except InternalError as e:
print("Something went wrong on the ProcessOut side. This is extremely rare. " + str(e))
require "processout"
# Different type of exceptions may be thrown by the
# ProcessOut's Python library, depending on the situation.
begin
# Some ProcessOut related code
rescue ProcessOut::AuthenticationError => e:
puts "Your API credentials couldn't be verified. " + str(e)
rescue ProcessOut::NotFoundError => e:
print("The requested resource could not be found. " + str(e))
rescue ProcessOut::ValidationError => e:
print("This error describes a validation error. " + str(e))
rescue ProcessOut::GenericError => e:
print("This is an error that didn't match any of the above. " + str(e))
rescue ProcessOut::InternalError => e:
print("Something went wrong on the ProcessOut side. This is extremely rare. " + str(e))
end
<?php
// Different type of exceptions may be thrown by the
// ProcessOut's PHP library, depending on the situation.
try
{
// Some ProcessOut related code
}
catch(ProcessOut\Exceptions\AuthenticationException $e)
{
// Your API credentials couldn't be verified
echo $e->getMessage();
}
catch(ProcessOut\Exceptions\NotFoundException $e)
{
// The requested resource could not be found
echo $e->getMessage();
}
catch(ProcessOut\Exceptions\ValidationException $e)
{
// This error describes a validation error
echo $e->getMessage();
}
catch(ProcessOut\Exceptions\GenericException $e)
{
// This is an error that didn't match any of the above
echo $e->getMessage();
}
catch(ProcessOut\Exceptions\InternalException $e)
{
// Something went wrong on the ProcessOut side. This
// is extremely rare
echo $e->getMessage();
}
// Different type of errors are returned by the ProcessOut's
// Go library, depending on the situation
switch e := err.(type) {
case *processout.AuthenticationError:
// Your API credentials couldn't be verified
case *processout.NotFoundError:
// The requested resource could not be found
case *processout.ValidationError:
// This error describes a validation error
case *processout.GenericError:
// This is an error that didn't match any of the above
case *processout.InternalError:
// Something went wrong on the ProcessOut side. This
// is extremely rare
default:
// The error comes from somewhere else, perhaps
// json unmarshaller
}
To make it easy for developers to handle errors in their applications, ProcessOut provides a set of class/objects to programmatically handle each different case.
Errors
Authentication error |
Your API credentials could not be verified |
Not found error |
The requested resource could not be found |
Validation error |
The request contained a field that couldn’t be validated |
Generic error |
An error that didn’t match any of the above |
Internal error |
Something went wrong on the ProcessOut side. This is extremely rare |
Help and support
We’d be glad to help you with any problem you may have during the integration of ProcessOut in your application. Feel free to contact us!
Metadata
It is possible to add context to the main ProcessOut resources (such as invoices, customers or subscriptions). Such context can range from the country of the customer to some internal ID you have on your side to track the order.
Some keywords in the metadata are reserved for specific uses:
- taxes_amount is zero or positive number representing the taxes included in the
amount
- shipping_amount is a zero or positive number representing the shipping costs included in the
amount
Payments
Invoices
An invoice is the core resource for a merchant who wants to accept payments online using the ProcessOut API. To start using invoices, let’s create one.
Attributes
id string Read-only |
|
url string Read-only |
URL to the ProcessOut checkout page |
customer customer_id Customer expandable |
Customer linked to the invoice |
transaction transaction_id Transaction expandable |
Transaction generated by the invoice |
subscription subscription_id Subscription expandable |
Subscription for which the invoice was automatically generated. Automatically set by ProcessOut |
token token_id Token expandable |
Token used (or to be used) to capture the payment. This token must belong to the customer linked to the invoice, if any |
details list of InvoiceDetails |
Details about the invoice, in the form of a list of InvoiceDetail object- see below for object reference |
risk object of InvoiceRisk |
Risk about the invoice, in the form of a list of Risk object- see below for object reference |
device object of InvoiceDevice |
Device information about the invoice, in the form of a Device object- see below for object reference |
shipping object of InvoiceShipping |
Shipping information about the invoice, in the form of a Shipping object- see below for object reference |
name string Required |
Name of the invoice/item to sell Max 80 characters long |
statement_descriptor string |
Statement that will be shown on your customer’s bank account Max 22 characters long, should only contain letters, numbers, spaces and commas |
amount string Required |
Amount to be paid |
currency string Required |
Currency of the invoice, in the ISO 4217 format (ex: USD )Must be a valid ISO 4217 3 characters currency code |
merchant_initiator_type string |
For off-session transactions (i.e. payments initiated by the merchant and not the user), set this field to either recurring for subscription payments or one-off |
return_url string |
URL used to redirect the customer once the payment is placedMust be a valid URL |
cancel_url string |
URL used to redirect the customer when the payment is canceledMust be a valid URL |
metadata Metadata dictionary |
Context related to the invoice, key-value pair (string - string) |
sca_exemption_reason string |
Optional reason for requesting SCA exemption (Note: Must also be supported by the PSP. Please contact our support to know more!) Allowed values are: “low-value”, “trusted-beneficiary” or “transaction-risk-analysis” |
challenge_indicator string |
Optional challenge indicator field when requesting 3DS2 (Note: Must also be supported by the PSP. Please contact our support to know more!) Allowed values are: “no-preference”, “no-challenge-requested”, “challenge-requested”, “challenge-requested-mandate”, “no-challenge-requested-tra-performed”, “no-challenge-requested-data-share-only”, “no-challenge-requested-sca-performed”, “no-challenge-requested-whitelist-exemption”, “challenge-requested-whitelist-prompt” or “cb-scoring” |
tax object of InvoiceTax |
Tax information about the invoice, in the form of a Tax object- see below for object reference |
payment_type string |
Optional information about the payment type Allowed values are: “moto” or “ecommerce” |
sandbox boolean Read-only |
|
created_at RFC1123 date or timestamp Read-only |
Invoice detail attributes
name string Required |
Name of the invoice detail, corresponding to a receipt line Max 80 characters long |
type string |
Type of the invoice detail- can be a string containing anything Max 30 characters long |
amount string Required |
Amount represented by the invoice detail |
quantity integer |
Quantity represented by the invoice detail, defaults to 1 |
metadata Metadata dictionary |
Context related to the invoice detail, key-value pair (string - string) |
category string |
Category of the product. Can be food , entertainment , home , appliance , bidding , gift , technology , media , communication , health , sport , personal-service , professional-service , clothing , travel , transport or other |
reference string |
Reference of the product Max 255 characters long |
description string |
Description of the invoice detail Max 255 characters long |
brand string |
Brand of the product Max 80 characters long |
model string |
Model of the product Max 80 characters long |
discount_amount string |
Discount amount represented by the invoice detail |
condition string |
Condition of the product. Can be new , refurbished , used or other |
marketplace_merchant string |
Marketplace merchant ID of the invoice detail |
marketplace_merchant_is_business boolean |
Define whether or not the marketplace merchant is a business |
marketplace_merchant_created_at RFC1123 date or timestamp |
Date at which the merchant was created |
Risk attributes
score string |
Scoring of the invoice. There is no validation done on this field as it is used to forward risk information on compatible payment providers Max 12 characters long |
is_legit bool |
Define whether or not the invoice is legit |
skip_gateway_rules bool |
Skip payment gateway fraud engine rules (on compatible gateways only. Please contact us to know more.) |
Device attributes
id string |
ID of the device. Free form field, usually is a UUID generated by third party anti-fraud solutions Max 100 characters long |
channel string |
Channel used by the device. Can be web , ios , android or other |
ip_address string |
IP address of the device Must be a valid IP address |
Shipping attributes
amount string |
Amount of the shipping |
method string |
Delivery method. Can be web , collect-at-shop , relay , travel-station , home , shipping , locker or other . |
provider string |
Delivery provider Max 32 characters long |
delay string |
Shipment delay. Can be express , priority , standard or other . |
address1 string |
Primary address line where the shipment has to be sent Max 255 characters long |
address2 string |
Secondary address line where the shipment has to be sent Max 255 characters long |
state string |
State where the shipment has to be sent Max 80 characters long |
city string |
City where the shipment has to be sent Max 80 characters long |
country_code string |
Shipment’s address country code (ex: US , FR ) where it has to be sentMust be a valid ISO 3166 2 characters country code |
zip string |
ZIP code where the shipment has to be sent Max 16 characters long |
phone_number string |
Phone number of the shipment recipent Max 17 characters long (Note: “+” will be treated as “00”) |
expects_shipping_at RFC1123 date or timestamp |
Date at which the shipment is expected to be sent |
relay_store_name string |
The store name where the order must be collected from Max 100 characters long |
Tax attributes
amount string |
Amount is zero or positive number representing the taxes included in the amount |
rate string |
Rate is a number between 0 to 100 representing the rate of the taxes included in the amount |
Create an invoice
curl -X POST https://api.processout.com/invoices \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB \
-d customer_id="cust_LvjCcLOVe6iWn2aeCNhNmK7RbbG6K8XF" \
-d name="Amazing item" \
-d statement_descriptor="amazing item" \
-d amount="4.99" \
-d currency="USD"
var ProcessOut = require("processout");
var client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
client.newInvoice().create({
customer_id: "cust_LvjCcLOVe6iWn2aeCNhNmK7RbbG6K8XF",
name: "Amazing item",
statement_descriptor: "amazing item",
amount: "4.99",
currency: "USD"
}).then(function(invoice) {
//
}, function(err) {
// An error occured
});
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
invoice = client.new_invoice().create({
"customer_id": "cust_LvjCcLOVe6iWn2aeCNhNmK7RbbG6K8XF",
"name": "Amazing item",
"statement_descriptor": "amazing item",
"amount": "4.99",
"currency": "USD"
})
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
invoice = client.invoice.create(
"customer_id": "cust_LvjCcLOVe6iWn2aeCNhNmK7RbbG6K8XF",
name: "Amazing item",
statement_descriptor: "amazing item",
amount: "4.99",
currency: "USD"
)
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
$invoice = $client->newInvoice()->create(array(
"customer_id" => "cust_LvjCcLOVe6iWn2aeCNhNmK7RbbG6K8XF",
"name" => "Amazing item",
"statement_descriptor" => "amazing item",
"amount" => "4.99",
"currency" => "USD"
));
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
iv, err := client.NewInvoice().Create(processout.InvoiceCreateParameters{
Invoice: &processout.Invoice{
CustomerID: processout.String("cust_LvjCcLOVe6iWn2aeCNhNmK7RbbG6K8XF"),
Name: processout.String("Amazing item"),
StatementDescriptor: processout.String("amazing item"),
Amount: processout.String("4.99"),
Currency: processout.String("USD"),
},
})
Creating an invoice for your customers can be done on your server’s backend.
Simply create an Invoice resource with a name
, amount
and currency
.
Fetch an invoice
curl -X GET https://api.processout.com/invoices/iv_MgeLS2Rr3ZGwjqOvDvYSuWx7ce88luXl \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB
var ProcessOut = require("processout");
var client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
client.newInvoice().find("iv_MgeLS2Rr3ZGwjqOvDvYSuWx7ce88luXl").then(
function(invoice) {
// The invoice was fetched
}, function(err) {
// The invoice could not be found
});
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
invoice = client.new_invoice().find("iv_MgeLS2Rr3ZGwjqOvDvYSuWx7ce88luXl")
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
invoice = client.invoice.find("iv_MgeLS2Rr3ZGwjqOvDvYSuWx7ce88luXl")
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
$invoice = $client->newInvoice()->find("iv_MgeLS2Rr3ZGwjqOvDvYSuWx7ce88luXl");
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
iv, err := client.NewInvoice().Find("iv_MgeLS2Rr3ZGwjqOvDvYSuWx7ce88luXl")
Invoices can be fetched from ProcessOut by using their IDs. If the invoice could not be found, an error is thrown.
Capture an invoice
curl -X POST https://api.processout.com/invoices/iv_MgeLS2Rr3ZGwjqOvDvYSuWx7ce88luXl/capture \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB \
-d source=card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ
var ProcessOut = require("processout");
var client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
// The source could also be a token tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy
invoice.capture("card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ").then(
function(transaction) {
// The invoice was captured and returned a transaction
}, function(err) {
// The invoice could not be captured
});
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
# The source could also be a token tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy
transaction = invoice.capture("card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ")
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
# The source could also be a token tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy
transaction = invoice.capture("card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ")
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
// The source could also be a token tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy
$transaction = $invoice->capture("card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ");
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
// The source could also be a token tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy
tr, _ := iv.Capture("card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ")
Capturing an invoice is done by calling capture
on the invoice and passing
the source
to be used to capture the payment in the parameters. If an error
occured while capturing the payment, an error is thrown. Otherwise, the
transaction linked to the invoice is updated and returned.
Be sure to check the status field of the Transaction to make sure the payment fully made it through. If the payment is not yet completed, we will create new Events to keep you updated regarding the status of the transaction.
Capturing an invoice can be done using a card
, a Token or a
Gateway request.
It is also possible to partially capture a transaction using the capture_amount
flag in the request. However, beware that your PSPs need to support partial
captures as well, otherwise you’ll need to to do a full capture followed by a
partial refund to achieve a similar goal.
On compatible providers, you can provide a statement descriptor that differs from
the authorization. In order to do so, you can leverage the capture_statement_descriptor
field in the capture request to set this value. If no value is provided, we’ll take
the same statement descriptor as the authorization.
On compatible providers, you can provide a list of invoice detail IDs to capture. In order to do so, you can fill in the invoice_detail_ids
field in the capture request to set an array of invoice detail IDs you need. If no value is provided, we’ll use the whole invoice details list.
Authorize only & auto capture
curl -X POST https://api.processout.com/invoices/iv_MgeLS2Rr3ZGwjqOvDvYSuWx7ce88luXl/authorize \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB \
-d source=card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ \
-d auto_capture_at="2022-10-02T15:00:00Z" # optional if you want us to auto capture for you
var ProcessOut = require("processout");
var client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
// The source could also be a token tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy
invoice.authorize("card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ", {
// optional if you want us to auto capture for you
"auto_capture_at": "2022-10-02T15:00:00Z"
}).then(
function(transaction) {
// The invoice was authorized and returned a transaction
}, function(err) {
// The invoice could not be authorized
});
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
# The source could also be a token tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy
transaction = invoice.authorize("card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ", {
# optional if you want us to auto capture for you
"auto_capture_at": "2022-10-02T15:00:00Z"
})
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
# The source could also be a token tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy
transaction = invoice.authorize("card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ", (
# optional if you want us to auto capture for you
auto_capture_at: "2022-10-02T15:00:00Z"
))
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
// The source could also be a token tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy
$transaction = $invoice->authorize("card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ", array(
// optional if you want us to auto capture for you
"auto_capture_at" => "2022-10-02T15:00:00Z"
));
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
// The source could also be a token tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy
tr, _ := iv.Authorize("card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ", InvoiceAuthorizeParameters{
AutoCaptureAt: "2022-10-02T15:00:00Z",
})
Instead of directly capturing a transaction, it’s also possible to execute a transaction in two phases: the authorization, which confirms and locks the funds on your user’s bank account but without doing the actual money movement, and the capture which initiates the money settlement.
ProcessOut offers two ways of executing a two-step transaction: either handling the authorization and capture steps yourself, or performing the authorization and letting us auto capture the transaction at a later date for you.
To manually capture after an authorization, simply call capture
endpoint. To set up
the auto capture, you can send the auto_capture_at
field during the authorization, with the
RFC3339 date at which the auto capture should be performed.
Keep in a mind an authorization usually only lasts for 7 days, after which the capture may fail.
Increment authorization
curl -X POST https://api.processout.com/invoices/iv_MgeLS2Rr3ZGwjqOvDvYSuWx7ce88luXl/increment_authorization \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB
-d amount="10.00"
var ProcessOut = require("processout");
var client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
invoice.incrementAuthorization("iv_MgeLS2Rr3ZGwjqOvDvYSuWx7ce88luXl","10.00").then(
function(transaction) {
// The authorization amount was incremented and returned a transaction
}, function(err) {
// The The authorization amount could not be incremented
});
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
transaction = invoice.increment_authorization("iv_MgeLS2Rr3ZGwjqOvDvYSuWx7ce88luXl","10.00")
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
transaction = invoice.increment_authorization("iv_MgeLS2Rr3ZGwjqOvDvYSuWx7ce88luXl","10.00")
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
$transaction = $invoice->incrementAuthorization("10.00");
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
tr, _ := iv.IncrementAuthorization("10.00")
It is possible to increment the amount authorized on a payment by submitting incremental authorizations. On the authorization request the value of the incremental property has to be true and the status of the transaction has to be authorized. (Note: Must also be supported by the PSP. Please contact our support to know more!)
Void an invoice
curl -X POST https://api.processout.com/invoices/iv_MgeLS2Rr3ZGwjqOvDvYSuWx7ce88luXl/void \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB
var ProcessOut = require("processout");
var client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
// The source could also be a token tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy
invoice.void().then(
function(transaction) {
// The invoice was voided and returned a transaction
}, function(err) {
// The invoice could not be voided
});
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
transaction = invoice.void()
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
transaction = invoice.void()
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
$transaction = $invoice->void();
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
tr, _ := iv.Void()
Voiding an invoice is meant to cancel a previously authorized transaction (and
can therefore not be done on a transaction that’s not with an authorized
state).
Voiding an invoice is done by calling void
on the invoice, and doesn’t need
any extra parameter. If an error occured while capturing the payment, an error
is thrown. Otherwise, the transaction linked to the invoice is updated and returned.
%>
Customers
Customers contain data related to your customers. You can store their name, email and address, but there’s also a metadata field that can be used to store additional data if needed.
Attributes
id string Read-only |
|
default_token default_token_id Token expandable |
Default token of the customer, used when charging directly using the customer ID as the source |
tokens list of Tokens expandable |
Tokens belonging to the customer (can be cards or other payment methods) |
subscriptions list of Subscriptions expandable |
Subscriptions belonging to the customer (in any subscription state) |
transactions list of Transactions expandable |
Transactions belonging to the customer (can be any transaction state) |
balance string |
Balance of the customer. This field is only used by the internal subscriptions engine to compute charges for plan changes- in most cases, do not update this field yourself |
currency string |
Currency of the customer balance- mostly automatically set by the internal subscriptions engine. Once set, it cannot be changed |
email string |
Customer’s email Must be a valid email |
first_name string |
First name of the customer Max 80 characters long |
last_name string |
Last name of the customer Max 80 characters long |
address1 string |
Primary address line of the customer Max 80 characters long |
address2 string |
Secondary address line of the customer Max 80 characters long |
city string |
City of the customer Max 80 characters long |
state string |
State of the customer Max 80 characters long |
zip string |
ZIP code of the customer Max 16 characters long |
country_code string |
Customer’s address country code (ex: US , FR )Must be a valid ISO 3166 2 characters country code |
phone_number string |
Phone number of the customer Max 17 characters long (Note: “+” will be treated as “00”) |
legal_document string |
Legal document number. Required in some countries Max 255 characters long; example for a CPF document in Brazil: 853.513.468-93 |
ip_address string |
IP address of the customer Must be a valid IP address |
sex string |
Sex of the customer. Can be male or female . |
date_of_birth RFC1123 date or timestamp |
Date of birth of the customer. |
is_business boolean |
Define whether or not the customer is a business |
metadata Metadata dictionary |
Context related to the customer, key-value pair (string - string) |
registered_at RFC1123 date or timestamp |
Date at which the customer was registered on your platform. Will default to created_at if empty. |
sandbox boolean Read-only |
|
created_at RFC1123 date or timestamp Read-only |
Create a customer
curl -X POST https://api.processout.com/customers \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB \
-d email="john@smith.com" \
-d first_name="John" \
-d last_name="Smith"
var ProcessOut = require("processout");
var client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
var customer = client.newCustomer().create({
"email": "john@smith.com",
"first_name": "John",
"last_name": "Smith"
}).then(function(customer) {
//
}, function(err) {
// An error occured
});
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
customer = client.new_customer().create({
"email": "john@smith.com",
"first_name": "John",
"last_name": "Smith"
})
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
customer = client.customer.create(
email: "john@smith.com",
first_name: "John",
last_name: "Smith"
)
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
$customer = $client->newCustomer()->create(array(
"email" => "john@smith.com",
"first_name" => "John",
"last_name" => "Smith"
));
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
cust, err := client.NewCustomer().Create(processout.CustomerCreateParameters{
Customer: &processout.Customer{
Email: processout.String("john@smith.com"),
FirstName: processout.String("John"),
LastName: processout.String("Smith"),
},
})
Once the customer is created, ProcessOut will return its resource ID
.
Storing this information on your backend may be useful if you want to
easily find which ProcessOut Customer belongs to which of your internal
users.
It is also possible to store metadata in your ProcessOut customers. Said metadata could be anything, from the ID of the user in your systems to the country of the customer.
Fetch a customer
curl -X GET https://api.processout.com/customers/cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB
var ProcessOut = require("processout");
var client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
client.newCustomer().find("cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb").then(
function(customer) {
//
}, function(err) {
// An error occured
});
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
customer = client.new_customer().find("cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb")
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
customer = client.customer.find("cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb")
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
$customer = $client->newCustomer()->find("cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb");
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
cust, err := client.NewCustomer().Find("cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb")
It is possible to fetch a customer by its ID. An error is thrown if the customer could not be found.
Update a customer
curl -X PUT https://api.processout.com/customers/cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB \
-d first_name="New Name"
var ProcessOut = require("processout");
var client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
customer.setFirstName("New name");
customer.save();
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
customer.first_name = "New name"
customer.save()
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
customer.first_name = "New name"
customer.save
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
$customer->setFirstName("New name");
$customer->save();
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
cust.FirstName = processout.String("New name")
cust.Save()
Update the customer attributes. You must use a previously created or fetched customer object in order to guarantee data integrity of the customer object.
Delete a customer
curl -X DELETE https://api.processout.com/customers/cust_LvjCcLOVe6iWn2aeCNhNmK7RbbG6K8XF \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB
var ProcessOut = require("processout");
var client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
client.newCustomer({
id: "cust_LvjCcLOVe6iWn2aeCNhNmK7RbbG6K8XF"
}).delete().then(
function(ok) {
//
}, function() {});
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
customer = client.new_customer({
"id": "cust_LvjCcLOVe6iWn2aeCNhNmK7RbbG6K8XF"
}).delete()
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
customer = client.customer(
id: "cust_LvjCcLOVe6iWn2aeCNhNmK7RbbG6K8XF"
).delete
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
$customer = $client->newCustomer(array(
"id" => "cust_LvjCcLOVe6iWn2aeCNhNmK7RbbG6K8XF"
))->delete();
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
cust, _ := client.NewCustomer(&processout.Customer{
ID: processout.String("cust_LvjCcLOVe6iWn2aeCNhNmK7RbbG6K8XF"),
}).Delete()
Deleting a customer is irreversible and cannot be undone. An error is thrown if the customer could not be deleted.
Cards
Cards resources are card objects created using ProcessOut.js. A card object is an immutable object that should only be used once. Once the card has been used to capture a payment or create a customer token, the card object may not be used anymore.
For this reason, if you wish to capture several payments using the card (at once or in the future), you must create a customer token.
ProcessOut will also fire events when a card is going to expire so that you can ask your customers to update their payment details.
Attributes
id string Read-only |
|
device CardDevice |
Attributes of the device of the user tokenizing the card (such as IP Address etc) |
contact CardContact |
Card contact attributes |
token Token expandable |
Token created using this card object, if any |
scheme string Read-only |
Scheme of the card, such as Visa or Mastercard |
co_scheme string Read-only |
Co-scheme of the card, such as Carte Bancaire |
preferred_scheme string Read-only |
Preferred scheme of the card, mostly defined by your Customer and used in priority to process the Transaction |
type string Read-only |
Type of card, such as debit or credit |
bank_name string Read-only |
Card issuing bank |
brand string Read-only |
Brand of the card, such as Electron, Classic or Gold |
iin string Read-only |
Issuer identification number. Corresponds to first 6 digits of the card |
last_4_digits string Read-only |
Last 4 digits of the card |
exp_month integer Read-only |
Expiry year of the card |
exp_year string Read-only |
Expiry year of the card |
cvc_check string Read-only |
CVC check status. Can be pending , unavailable , unknown , failed , or passed |
avs_check string Read-only |
AVS check status. Can be pending , unavailable , unknown , failed , failed-name , failed-address , failed-postal , failed-address-passed-postal , failed-postal-passed-address , or passed |
name string |
Cardholder name Max 255 characters long |
metadata Metadata dictionary |
Context related to the card, key-value pair (string - string) |
sandbox boolean Read-only |
|
created_at RFC1123 date or timestamp Read-only |
Card device Attributes
request_origin string |
Origin of the request: coming directly from your users’ browser, or from your backend Use the value backend if you’re tokenizing from your backend |
channel string |
Channel of the device Can be web , ios , android or other |
ip_address string |
IP address of the cardholder Must be a valid IP address |
user_agent string |
User Agent header of the cardholder, if any |
header_accept string |
Accept header of the cardholder, if any |
app_color_depth string |
Supported color depth on the cardholder screen, if any |
app_java_enabled boolean |
Whether or not java is enabled on the cardholder device, null if unknonwn |
app_language string |
Language of the cardholder’s device, if any example: FR/fr |
app_screen_height integer |
Height in pixels of the cardholder’s screen |
app_screen_width integer |
Width in pixels of the cardholder’s screen |
app_timezone_offset integer |
Timezone offset of the user Timezone offset from UTC in minutes (from -12hr to +14hr) |
Card contact Attributes
address1 string |
Cardholder primary address line Max 255 characters long |
address2 string |
Cardholder secondary address line Max 255 characters long |
city string |
Cardholder city Max 255 characters long |
state string |
Cardholder state Max 255 characters long |
country_code string |
Cardholder country Must be a valid ISO 3166 2 characters country code |
zip string |
Cardholder zip Max 16 characters long |
Tokenize a card
curl -X POST https://api.processout.com/cards \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB \
-d name="John Smith" \
-d number=4242424242424242 \
-d exp_month=12 \
-d exp_year=2020 \
-d cvc2=200
// NodeJS is currently not supported for Cards (please use ProcessOut.js instead)
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
# Python is currently not supported for Cards
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
# Ruby is currently not supported for Cards
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
// PHP is currently not supported for Cards
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
// Go is currently not supported for Cards
Tokenizing a card on ProcessOut can be done using the Cards endpoint. It is most useful to merchants already PCI compliant. However, for most merchants and use-cases we strongly advise to use our ProcessOut.js and mobile SDKs to tokenize the cards, as these SDKs allow you to remove the need for complexe card data certifications (PCI-DSS).
Fetch a card
curl -X GET https://api.processout.com/cards/card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB
var ProcessOut = require("processout");
var client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
client.newCard().find("card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ").then(
function(card) {
//
}, function(err) {
// An error occured
});
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
card = client.new_card().find("card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ")
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
card = client.card.find("card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ")
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
$card = $client->newCard()->find("card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ");
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
card, err := client.NewCard().Find("card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ")
Retrieve a card to fetch data stored earlier during a tokenization call.
This API endpoint can also be used to detokenize a card if you own a PCI environment. Please talk to your ProcessOut account manager to learn more!
Tokens
Tokens are objects referencing to a customer payment method, and can be used to capture payments for your customers programmatically.
Tokens can reference objects such as cards
, but also tokens native to the
alternative payment gateways you use. For example, it is therefore possible to create tokens
for PayPal.
When activating a subscription, tokens are also automatically created and linked
to the subscription so that ProcessOut uses it under the hood to automatically
capture payments as the subscription iterates. Such tokens will be marked with
a is_subscription_only
set to true
, and can only be used on the subscription
they were created for. For this reason, you might want to avoid displaying
those tokens to your customers when listing their stored payment methods.
Attributes
id string Read-only |
|
customer customer_id Customer expandable |
Customer for which the token was created |
card card_id Card expandable |
Card used to create the token |
invoice invoice_id Invoice expandable |
Invoice used to verify the token |
type string Read-only |
Source used to create the token. Most of the time will be a card |
description string |
Description that will be sent to the tokenization gateway service |
is_subscription_only boolean Read-only |
Whether or not the token was created for a specific subscription |
verification_status boolean Read-only |
When a token has been requested to be verified, the status will be displayed using this field. The status can have the following values: success , pending , failed , not-requested and unknown |
is_default boolean Read-only |
Whether or not the token is the default customer token (i.e. the one used when capturing a payment using the customer ID as the source) |
metadata Metadata dictionary |
Context related to the customer, key-value pair (string - string) |
sandbox boolean Read-only |
|
created_at RFC1123 date or timestamp Read-only |
|
invoice_id string Read-only |
ID of the invoice used to verify the token |
manual_invoice_cancellation boolean Read-only |
If true, allows to refund or void the invoice manually following the token verification process |
Create a token
curl -X POST https://api.processout.com/customers/cust_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj/tokens \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB \
-d source=card_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj
var ProcessOut = require("processout");
var client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
client.newToken().create({
customer_id: "cust_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj",
source: "card_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj"
}).then(function(token) {
//
}, function(err) {
// An error occured
});
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
token = client.new_token().create({
"customer_id": "cust_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj",
"source": "card_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj"
})
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
token = client.token.create(
customer_id: "cust_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj",
source: "card_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj"
)
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
$token = $client->newToken()->create(array(
"customer_id" => "cust_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj",
"source" => "card_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj"
));
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
token, err := client.NewToken().Create(processout.TokenCreateParameters{
Token: &processout.Token{
CustomerID: processout.String("cust_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj"),
},
Source: "card_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj",
})
Creating a customer token can be done by providing a customer ID for which to
create the token, and a source. The source can be a card
, but also a
gateway request.
The ID of the token that was created should be stored in your application so you can capture payments using it later.
Fetch a token
curl -X GET https://api.processout.com/customers/cust_WtaVdUjAGpOlbLiYWYXBR67whr91Rlks/tokens/tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB
var ProcessOut = require("processout");
var client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
client.newToken().find("cust_WtaVdUjAGpOlbLiYWYXBR67whr91Rlks",
"tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy").then(
function(token) {
// And let's say our customer wants to remove its token
token.delete();
}, function(err) {
// The customer's token could not be fetched
});
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
token = client.new_token().find("cust_WtaVdUjAGpOlbLiYWYXBR67whr91Rlks",
"tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy")
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
token = client.token.find("cust_WtaVdUjAGpOlbLiYWYXBR67whr91Rlks",
"tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy")
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
$token = $client->newToken()->find("cust_WtaVdUjAGpOlbLiYWYXBR67whr91Rlks",
"tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy");
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
tok, err := client.NewToken().Find("cust_WtaVdUjAGpOlbLiYWYXBR67whr91Rlks",
"tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy")
Fetch a specific customer’s token
List a customer’s tokens
curl -X GET https://api.processout.com/customers/cust_WtaVdUjAGpOlbLiYWYXBR67whr91Rlks/tokens \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB
var ProcessOut = require("processout");
var client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
customer.fetchTokens().then(
function(tokens) {
// And let's say our customer wants to remove its first token
tokens[0].delete();
}, function(err) {
// The customer's tokens could not be fetched
});
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
tokens = customer.fetch_tokens()
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
tokens = customer.fetch_tokens()
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
$tokens = $customer->fetchTokens();
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
tok, _ := cust.FetchTokens()
Once some tokens have been created for a customer, it is possible to list them all.
Delete a token
curl -X DELETE https://api.processout.com/customers/cust_WtaVdUjAGpOlbLiYWYXBR67whr91Rlks/tokens/tok_aKrYfz903uXn9MV0p8ZH7Lfly2JGtZWh \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB
token.delete().then(
function(ok) {
//
}, function(err) {
// The token could not be deleted
});
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
token.delete()
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
token.delete
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
$token->delete();
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
tok.Delete()
Deleting a token is irreversible and cannot be undone. An error is thrown if the token could not be deleted.
Balances
Some payment providers allow customers to have Balances
saved for a Token
. If the token is associated with payment providers that support APMs, you can use ProcessOut APIs to check if the customer has any balance that can be used. Currently, the only supported balance method is vouchers
. If the customer doesn’t have any, you can then bill using other registered payment methods.
Balances
Attributes
vouchers list of Balance Read-only |
Contains all available vouchers to be used, and their values |
Balance
attributes
amount string Read-only |
Balance amount |
currency string Read-only |
Balance currency |
expiry RFC1123 date or timestamp Read-only |
Balance expiration date |
Fetch Balances
curl -X GET https://api.processout.com/balances/tokens/tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB
const ProcessOut = require("processout");
const client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
// ...
const balances = await client.newBalances().find("tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy");
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
# use customer payment token to retrieve any available balance
balances = client.new_balances().find("tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy")
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
# use customer payment token to retrieve any available balance
balances = client.balances.find("tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy")
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
// use customer payment token to retrieve any available balance
$balances = $client->newBalances()->find("tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy");
?>
import "github.com/processout/processout-go"
client := processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
// use customer payment token to retrieve any available balance
balances, err := client.NewBalances().Find("tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy")
Using the Find
method will allow you to find all available balances for the specified token_id
Transactions
Transactions are read-only objects linked to their corresponding invoice, representing the actual payment that occured on an invoice.
ProcessOut will automatically generate and/or update Transaction resources depending on the status of the payment.
Any metadata specified on an invoice will also be available in the metadata of its transaction for easy reference.
Attributes
id string Read-only |
|
invoice invoice_id Invoice expandable |
Invoice used to create the transaction, if any |
customer customer_id Customer expandable |
Customer linked to the transaction |
subscription subscription_id Subscription expandable |
Subscription used to create the transaction |
token token_id Token expandable |
Token used to capture the transaction |
card card_id Card expandable |
Card used to capture the transaction |
gateway_configuration gateway_configuration_id Gateway Configuration expandable |
Gateway configuration used to finally process the transaction |
operations List of Operations expandable |
The list of all the transaction operations (pending, failed or successful) made on the transactions, such as authorization , capture , refund and so on- see below for object reference |
name string Read-only |
Name of the Transaction |
amount string Read-only |
Amount requested when creating the transaction |
authorized_amount string Read-only |
Amount that was authorized for the transaction |
captured_amount string Read-only |
Amount that was captured for the transaction |
refunded_amount string Read-only |
Amount that was refunded for the transaction |
available_amount string Read-only |
Amount available for the transaction (captured - refunded) |
currency string Read-only |
Currency of the transaction |
authorized boolean Read-only |
Whether or not the transaction was authorized |
captured boolean Read-only |
Whether or not the transaction was captured |
status string Read-only |
Status of the transaction |
three_d_s_status string Read-only |
Status of the 3-D Secure authentication done on the transaction. Can be null if no authentication was performed |
error_code string Read-only |
Transaction error code when the payment has failed |
processout_fee string Read-only |
Fee taken by ProcessOut to handle the transaction |
estimated_fee string Read-only |
Gateway fee estimated before processing the payment |
gateway_fee string Read-only |
Fee taken by the payment gateway to process the payment |
metadata Metadata dictionary |
Context related to the transaction’s invoice, key-value pair (string - string) |
created_at RFC1123 date or timestamp Read-only |
Operation attributes
id string Read-only |
|
amount string Read-only |
Amount related to the transaction operation (can be negative) |
type string Read-only |
Type of the operation. Can be request , three_d_s_check , authorization , capture , void , refund , chargeback |
is_attempt boolean Read-only |
Whether or not the operation is the attempt |
has_failed boolean Read-only |
Whether or not the operation has failed. Typically, has_failed will only be set when is_attempt is false (i.e. when the operation got its result back, after attempting it) |
is_accountable boolean Read-only |
Whether or not the amount of the operation should be used to compute the actual amount of the transaction |
error_code string Read-only |
Operation error code, typically set when has_failed is true |
metadata Metadata dictionary |
Context related to the transaction’s invoice, key-value pair (string - string) |
created_at RFC1123 date or timestamp Read-only |
As seen in the transaction’s attributes, it also contains a status
, representing
the current status of the transaction. This status is automatically updated
by ProcessOut when an update occurs on the transaction.
You may find the full list of transaction statuses here ↗.
Fetch a transaction
curl -X GET https://api.processout.com/transactions/tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB
var ProcessOut = require("processout");
var client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
client.newTransaction().find("tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC").then(
function(transaction) {
// Transaction was fetched
}, function(err) {
// An error occured
});
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
transaction = client.new_transaction().find("tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC")
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
transaction = client.transaction.find("tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC")
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
$transaction = $client->newTransaction()->find("tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC");
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
tr, err := client.NewTransaction().Find("tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC")
It is possible to fetch a transaction by its ID. An error is thrown if the transaction could not be found.
List customers’ transactions
curl -X GET https://api.processout.com/customers/cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb/transactions \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB
var ProcessOut = require("processout");
var client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
client.newCustomer({
id: "cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb"
}).fetchTransactions().then(
function(transactions) {
// Transactions were fetched
}, function(err) {
// An error occured
});
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
transaction = client.new_customer({
"id": "cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb"
}).fetch_transactions()
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
transaction = client.customer(
id: "cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb"
).fetch_transactions()
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
$transaction = $client->newCustomer(array(
"id" => "cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb"
))->fetchTransactions();
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
tr, err := client.NewCustomer(&processout.Customer{
ID: "cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb",
}).FetchTransactions()
Paginate over all the transactions associated to a customer. Learn more about how to paginate on ProcessOut here. An error is thrown if the customer could not be found.
Refunds
Once a payment is placed, the merchant has the ability to refund a part or the entire transaction amount. This is especially useful when doing customer support, as refunds are generally free compared to chargebacks. It is strongly advised to issue a refund (full or partial) when you think a transaction is fraudulent.
Attributes
id string Read-only |
|
transaction transaction_id Transaction expandable |
Transaction for which the refund was issued |
reason string Required |
Reason for the refund. Can be either customer_request , duplicate or fraud |
information string |
Additional information regarding the refund |
amount string Required |
Refund amount applied on the transaction |
metadata Metadata dictionary |
Context related to the customer, key-value pair (string - string) |
sandbox boolean Read-only |
|
invoice_detail_ids list of string |
List of invoice detail IDs for which a refund is made |
Issue a refund
curl -X POST https://api.processout.com/transactions/tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC/refunds \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB \
-d reason=customer_request \
-d amount=4.99
var ProcessOut = require("processout");
var client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
client.newRefund().create({
transaction_id: "tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC",
reason: "customer_request",
amount: "4.99"
}).then(function(refund) {
//
}, function(err) {
// An error occured
});
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
refund = client.new_refund().create({
"transaction_id": "tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC",
"reason": "customer_request",
"amount": "4.99"
})
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
refund = client.refund.create(
transaction_id: "tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC",
reason: "customer_request",
amount: "4.99"
)
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
$refund = $client->newRefund()->create(array(
"transaction_id" => "tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC",
"reason" => "customer_request",
"amount" => "4.99"
));
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
refund, err := client.NewRefund().Create(processout.RefundCreateParameters{
Refund: &processout.Refund{
TransactionID: processout.String("tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC"),
Reason: processout.String("customer_request"),
Amount: processout.String("4.99"),
},
})
Refunding a transaction can be done by providing the transaction ID to be
refunded, as well as the amount and a reason for the refund, which can be
either customer_request
, duplicate
or fraud
.
The amount can also be left empty to operate a full refund on the transaction. In case partial refunds were previously applied on the transaction, leaving the refund amount empty will refund what’s left of the transaction amount.
The invoice_detail_ids
may be omitted. In this case full list of invoice details
will be passed to provider.
Fetch a refund
curl -X GET https://api.processout.com/transactions/tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC/refunds/refd_QKliea9OGXtLBXcar2SJjfD11aY0J2SH \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB
var ProcessOut = require("processout");
var client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
client.newRefund().find("tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC",
"refd_QKliea9OGXtLBXcar2SJjfD11aY0J2SH").then(
function(refund) {
// Refund was fetched
}, function(err) {
// An error occured
});
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
refund = client.new_refund().find("tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC",
"refd_QKliea9OGXtLBXcar2SJjfD11aY0J2SH")
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
refund = client.refund.find("tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC",
"refd_QKliea9OGXtLBXcar2SJjfD11aY0J2SH")
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
$refund = $client->newRefund()->find("tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC",
"refd_QKliea9OGXtLBXcar2SJjfD11aY0J2SH");
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
refund, err := client.NewRefund().Find("tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC",
"refd_QKliea9OGXtLBXcar2SJjfD11aY0J2SH")
It is possible to fetch a transaction’s refund by its ID. An error is thrown if the refund could not be found for the specified transaction.
Events
Below is an example of the content of the
data
field of an event.
{
"name": "transaction.captured",
"sandbox": false,
"transaction": {
"id": "tr_WZIEktoQtzflmfv4aJA645Qwj3JzaVGa",
"invoice_id": "iv_CKL1LOXGZ71wYAqGCyfDFhDTR3MGPkLY",
"invoice": {
"id":"proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"name":"T-Shirt Size M",
"price":"22.99",
"total":"22.99",
"currency":"USD",
"request_email":true,
"request_shipping":false,
"return_url":"https://sales.appgrouplimited.com",
"cancel_url":null,
"sandbox":false,
"url":"https://checkout.processout.com/iv_...",
"created_at":"2016-11-05T13:05:27.136003Z"
},
"customer_id": "cust_74qLxAbCpEYOxiBBwXTPKTP4QgTstude",
"customer":{
"id":"cust_74qLxAbCpEYOxiBBwXTPKTP4QgTstude",
"balance":"0",
"currency":"USD",
"email":"john@gmail.com",
"first_name":"",
"last_name":"",
"address1":"",
"address2":"",
"city":"",
"state":"",
"zip":"",
"country_code":"",
"metadata":{},
"sandbox":false,
"created_at":"2016-11-05T13:05:47.963398Z",
"transactions_count":1,
"subscriptions_count":0,
"mrr_local":0,
"total_revenues_local":22.99
},
"card_id": "card_knolIrMhVyZXLyYwZ56o6jxgYslH0Sqy",
"card": {
"address1": null,
"address2": null,
"avs_check": "unknown",
"cvc_check": "passed",
"bank_name": "",
"brand": "",
"city": null,
"country_code": "US",
"created_at": "2017-03-17T17:05:08.675622Z",
"exp_month": 10,
"exp_year": 2018,
"expires_soon": false,
"id": "card_knolIrMhVyZXLyYwZ56o6jxgYslH0Sqy",
"iin": "424242",
"last_4_digits": "4242",
"metadata": {},
"name": null,
"project_id": "9b66d6da-45e7-489f-bf91-0a012fe60490",
"sandbox": false,
"scheme": "visa",
"state": null,
"type": "credit",
"zip": null
},
"refunds": [],
"status": "completed",
"created_at": "2017-03-17T17:04:55.813311Z",
"amount": "22.99",
"authorized": true,
"authorized_amount": "22.99",
"available_amount": "22.99",
"captured": true,
"captured_amount": "22.99",
"refunded_amount": "0",
"currency": "EUR",
"details": {
"country": null
},
"error_code": null,
"estimated_fee": "0.57",
"gateway_fee": "0.51",
"gateway_fee_details": {
"exchange_fee": "0",
"processing_fee": "0.51",
"refund_fee": "0"
},
"gateway_name": "stripe",
"metadata": {},
"name": "T-Shirt Size M",
"sandbox": false
}
}
When a resource’s state changes, ProcessOut will create an Event
object which can
be programmatically fetched. This can be used to notify your application
when a transaction gets completed, or when a subscription iterates to its next
period, but can also have many other possible applications.
You can find all the events we currently fire here.
It is also important to note that events are extremely powerful when they’re coupled with webhooks. As soon as an event is created, we’ll send a request to your web application to notify you of this new event so it can fetched and processed.
You may find on the right pane an example of what the content of the data
field
might look like. The data is basically composed of the object the event describes
at the top level, and this object has its first level resources expanded (when
available). If you wish to access deeper resources, you will need to fetch those
from the API.
Attributes
id string Read-only |
|
name string Read-only |
Name of the event corresponding to the action |
data json object Read-only |
Data linked to the event |
sandbox boolean Read-only |
|
fired_at RFC1123 date or timestamp Read-only |
Fetch an event
curl -X GET https://api.processout.com/events/ev_T3wg9169RyGLnf1BIgTjLhrolEZU1DSb \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB
var ProcessOut = require("processout");
var client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
client.newEvent().find("ev_T3wg9169RyGLnf1BIgTjLhrolEZU1DSb").then(
function(event) {
// We may now access the event
}, function(err) {
// An error occured
});
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
event = client.new_event().find("ev_T3wg9169RyGLnf1BIgTjLhrolEZU1DSb")
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
event = client.event.find("ev_T3wg9169RyGLnf1BIgTjLhrolEZU1DSb")
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
$event = $client->newEvent()->find("ev_T3wg9169RyGLnf1BIgTjLhrolEZU1DSb");
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
ev, err := client.NewEvent().Find("ev_T3wg9169RyGLnf1BIgTjLhrolEZU1DSb")
Fetch an event by its ID. An error is thrown when the event could not be found.
Transaction events
The transaction events are created when an update regarding a transaction
occurs. Because transactions are strongly linked to invoices, you can
listen to a transaction event to be notified of an invoice event. The transaction
event will always contain an invoice_id
field containing the id
of the invoice
it was linked to.
Events
transaction.requested |
A payment request was made. No payment has been placed yet |
transaction.authorized |
The payment has been authorized. It is not yet available in your balance and must first be captured |
transaction.captured |
The payment has been captured and funds have been confirmed |
transaction.failed |
The payment has failed |
transaction.voided |
The transaction has been voided and can’t be captured anymore |
transaction.refunded |
You issued a refund on the transaction. The amount of the refund can be found in the field refunded_amount and in the refunds objects list |
transaction.chargeback.created |
A chargeback has been filled by your customer |
transaction.chargeback.won |
The previously filled chargeback was resolved in your favor |
transaction.chargeback.lost |
The previously filled chargeback was resolved in your customer’s favor |
transaction.chargeback.retrieval-request |
The payment was previously completed but the customer does not recognize the payment and is asking for information |
transaction.chargeback.fraud-notification |
The payment was previously completed but the bank is notifying you a chargeback might be on its way |
Subscription events
The subscription events are fred when an update regarding a subscription occurs.
Note: When a subscription iterates, a new invoice and its associated transaction will be created and marked as completed, and its corresponding event will also be fired.
Events
subscription.created |
A new subscription resource was created |
subscription.started |
The subscription started |
subscription.iterated |
The customer paid for the current iteration of its subscription |
subscription.trial.ending_soon |
The subscription trial is ending soon. You may use this event to notify your customer to update their billing details if not done yet |
subscription.trial.ended |
The subscription trial ended |
subscription.payment_failed |
The payment of the current subscription period failed |
subscription.canceled |
The customer’s subscription was canceled Note: It might have been canceled because the payment gateway refused your customer’s payment (ex: when the credit card expired). The reason of the cancellation is available in the cancellation_reason attribute of the subscription |
Customer events
The customer events are fired when an update regarding a customer occurs.
Events
customer.created |
A new customer resource was created |
customer.updated |
The customer resource was updated |
customer.deleted |
The customer resource was deleted |
Customer token events
The customer token events are fired when an update regarding a customer token occurs.
Events
customer.token.created |
A new customer token resource was created |
customer.token.updated |
The customer token resource was updated |
customer.token.deleted |
The customer token resource was deleted |
customer.token.verified |
The customer token was verified successfully |
customer.token.verification.failed |
The customer token verification failed |
Plan events
The plan events are fired when an update regarding a plan occurs.
Events
plan.created |
A new plan resource was created |
plan.updated |
The plan resource was updated |
plan.deleted |
The plan resource was deleted |
Product events
The product events are fired when an update regarding a product occurs.
Events
product.created |
A new product resource was created |
product.updated |
The product resource was updated |
product.deleted |
The product resource was deleted |
Coupon events
The coupon events are fired when an update regarding a coupon occurs.
Events
coupon.created |
A new coupon resource was created |
coupon.updated |
The coupon resource was updated |
coupon.deleted |
The coupon resource was deleted |
Webhooks
Processing events can be done through webhooks (also called callbacks or Instant Payment Notification: IPN). It is essentially a web request made to your web application, notifying you of the new event. Webhooks can be used to automatically deliver an item upon successful payment for example.
However, as many payment gateways can be used at the same time, ProcessOut provides webhooks containing unified, normalized and easy to use data, as well as transaction states corresponding to the triggered event.
Pre-requisites
In order to start receiving webhooks, you must add your webhook endpoint
s in your
ProcessOut dashboard.
You should also note that we will always POST
a json encoded body request
to your application. Therefore, you should accept POST requests with a json
encoded body.
Furthermore, you should remove all CSRF protection on your endpoints receiving webhooks. Most frameworks and CMS activate it by default, which could prevent ProcessOut from correctly posting webhooks to your application.
Custom URL per Invoice
curl -X POST https://api.processout.com/invoices \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB \
-d customer_id="cust_LvjCcLOVe6iWn2aeCNhNmK7RbbG6K8XF" \
-d name="Amazing item" \
-d amount="4.99" \
-d currency="USD" \
-d webhook_url="https://superstore.com/webhooks"
var ProcessOut = require("processout");
var client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
client.newInvoice().create({
customer_id: "cust_LvjCcLOVe6iWn2aeCNhNmK7RbbG6K8XF",
name: "Amazing item",
amount: "4.99",
currency: "USD",
webhook_url: "https://superstore.com/webhooks"
}).then(function(invoice) {
//
}, function(err) {
// An error occured
});
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
invoice = client.new_invoice().create({
"customer_id": "cust_LvjCcLOVe6iWn2aeCNhNmK7RbbG6K8XF",
"name": "Amazing item",
"amount": "4.99",
"currency": "USD",
"webhook_url": "https://superstore.com/webhooks"
})
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
invoice = client.invoice.create(
"customer_id": "cust_LvjCcLOVe6iWn2aeCNhNmK7RbbG6K8XF",
name: "Amazing item",
amount: "4.99",
currency: "USD",
webhook_url: "https://superstore.com/webhooks"
)
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
$invoice = $client->newInvoice()->create(array(
"customer_id" => "cust_LvjCcLOVe6iWn2aeCNhNmK7RbbG6K8XF",
"name" => "Amazing item",
"amount" => "4.99",
"currency" => "USD",
"webhook_url" => "https://superstore.com/webhooks"
));
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
iv, err := client.NewInvoice().Create(processout.InvoiceCreateParameters{
Invoice: &processout.Invoice{
CustomerID: processout.String("cust_LvjCcLOVe6iWn2aeCNhNmK7RbbG6K8XF"),
Name: processout.String("Amazing item"),
Amount: processout.String("4.99"),
Currency: processout.String("USD"),
WebhookURL: processout.String("https://superstore.com/webhooks"),
},
})
Sometimes, it’s also important for you to define custom webhook endpoints per order.
You can achieve this by providing a webhook_url
during the POST
call on
/invoices
(i.e. when you’re creating a new Invoice. Events
specific to the invoice the webhook_url
is associated with will be sent to
this URL. The other webhook endpoints you have defined at a global level on
your ProcessOut project will still be used as well on Invoices that have a custom
webhook_url
defined.
Usage
# Webhooks are not supported with cURL.
var ProcessOut = require("processout");
var client = new ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
// req is filled with the decoded json data from the request body
client.newEvent().find(req["event_id"]).then(function(event) {
// We may now access the event
var data = event.getData();
switch (data["name"]) {
case "invoice.completed":
// Successful payment
break;
case "invoice.pending":
// Payment still needs some time to be processed
break;
// ...
default:
console.log("Unknown webhook action");
return;
}
}, function(err) {
// An error occured, most likely the event was coming from an
// untrusted source
});
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
# req is filled with the decoded json data from the request body
event = client.new_event().find(req["event_id"])
data = event.data
if data["name"] == "invoice.completed":
# Successful payment
pass
elif data["name"] == "invoice.pending":
# Payment still needs some time to be processed
pass
# ...
else:
# Shouldn't be here..
print("Unknown webhook action")
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
# req is filled with the decoded json data from the request body
event = client.event.find(req.event_id)
data = event.data
if data["name"] == "invoice.completed"
# Successful payment
elsif data["name"] == "invoice.pending"
# Payment still needs some time to be processed
# ...
else
# Shouldn't be here..
puts "Unknown webhook action"
end
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
$reqRaw = trim(file_get_contents("php://input"));
$req = json_decode($reqRaw, true);
$event = $client->newEvent()->find($req["event_id"]);
$data = $event->getData();
switch($data["name"])
{
case "invoice.completed":
// Successful payment
break;
case "invoice.pending":
// Payment still needs some time to be processed
break;
// ...
default:
echo "Unknown webhook action"; exit();
}
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
// EventData is the definition of a ProcessOut Event data
type EventData struct {
Name string `json:"name"`
Sandbox bool `json:"sandbox"`
Invoice *processout.Invoice `json:"invoice"`
}
// ProcessOutWebhook is the definition of a ProcessOut webhook
type ProcessOutWebhook struct {
EventID string `json:"event_id"`
}
func handleProcessOutWebhooks(w http.ResponseWriter,
r *http.Request) {
defer r.Body.Close()
reqRaw, err := ioutil.ReadAll(r.Body)
if err != nil {
panic(err)
}
// Decode the webhook
webhook := &ProcessOutWebhook{}
json.Unmarshal(reqRaw, &webhook)
// Fetching the associated event
event, err := client.NewEvent().Find(webhook.EventID)
if err != nil {
// Webhook not found, most likely coming from an
// insecure source
w.WriteHeader(http.StatusBadRequest)
return
}
e, _ := event.(EventData)
switch e.Name {
case "invoice.completed":
// Successful payment
case "invoice.pending":
// Payment still needs some time to be processed
// ...
default:
// Return an HTTP OK response so that unsuported
// webhooks do not get sent again
w.WriteHeader(http.StatusOK)
return
}
}
The webhooks your web application receives only contain the ID of the event, which can then be fetched through the ProcessOut API to access the actual data of the event.
Payouts
When processing payments, it’s important for businesses to be able to track cash, especially if several PSPs (Payment Service Providers) are being used.
When possible/available, ProcessOut will communicate to your PSPs using your API keys or through reports to fetch reconciliation/settlement reports from them and automatically match them with the transactions you processed on ProcessOut.
Once these reports are ingested by ProcessOut, new Payout
objects are created,
each of them containing items that correspond to lines involved in the final
amount transfered to your bank account (positive amounts for successful payments,
but negative ones for refunds or chargebacks as well).
Please note that Payouts are not available in sandbox mode.
Pre-requisites
Because each PSP handles reports in a different way, please reach out to your account representative at ProcessOut to see how yours are specifically handled.
Attributes
id string Read-only |
|
items list of PayoutItems expandable |
Items listed in the payout |
status string Read-only |
Status of the payout. Can be pending , in-flight , received , canceled or failed |
amount string Read-only |
Amount of the payout wired to your bank |
currency string Read-only |
Currency of the payout |
bank_name string Read-only |
Name of the bank to which the payout was issued, if available |
bank_summary string Read-only |
Bank summary of the payout, if available |
sales_transactions integer Read-only |
Number of transactions involved in this payout |
sales_volume string Read-only |
Transactions volume involved in this payout |
refunds_transactions integer Read-only |
Number of refunds involved in this payout |
refunds_volume string Read-only |
Refunds volume involved in this payout |
chargebacks_transactions integer Read-only |
Number of chargebacks involved in this payout |
chargebacks_volume string Read-only |
Chargebacks volume involved in this payout |
metadata Metadata dictionary Read-only |
Context related to the payout, key-value pair (string - string) |
fees string Read-only |
Fees taken by the PSP |
adjustments string Read-only |
Adjustments applied by the PSP to the final payout amount |
reserve string Read-only |
Reserve kept by the PSP for the payout |
created_at RFC1123 date or timestamp Read-only |
Payout item attributes
id string Read-only |
|
transaction transaction_id Transaction expandable |
Transaction involved in this payout item. Can be null if the item isn’t linked to a particular transaction, or is a transaction processed outside of ProcessOut |
type string Read-only |
Type of the payout item. Can be sale , refund , chargeback , fee , adjustment , reserve |
gateway_resource_id string Read-only |
ID used by the PSP to reference that payout item |
amount string Read-only |
Amount of the payout item (can be negative) |
fees string Read-only |
Fees taken on this specific payout item |
metadata Metadata dictionary Read-only |
Context related to the transaction’s invoice, key-value pair (string - string) |
created_at RFC1123 date or timestamp Read-only |
List your payouts
curl -X GET https://api.processout.com/payouts \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB
// Javascript is currently not supported for Payouts
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
# Python is currently not supported for Payouts
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
# Ruby is currently not supported for Payouts
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
// PHP is currently not supported for Payouts
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
// Go is currently not supported for Payouts
Paginate through all your payouts.
If you expand the items
field of the payout, only the first few items will be
returned. If you’d like to access all the items of a specific payout, you can
paginate through them using the payout ID.
Paginate through payout items
curl -X GET https://api.processout.com/payouts/payt_3vfLtjoiQxpXZrdd6dc8Qgxxe26vy0aH/items \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB
// NodeJS is currently not supported for Payouts
import processout
client = processout.ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
# Python is currently not supported for Payouts
require "processout"
client = ProcessOut::Client.new(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB")
# Ruby is currently not supported for Payouts
<?php
$client = new \ProcessOut\ProcessOut(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB");
// PHP is currently not supported for Payouts
import "github.com/processout/processout-go"
var client = processout.New(
"test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
"key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB",
)
// Go is currently not supported for Payouts
Paginate through all the items of a specific payout.
Analytics/Monitoring
Ingestion introduction
ProcessOut, on top of its payments processing gateway, provides tools to help merchants analyze, benchmark and monitor their payments performance through our Telescope and Monitoring products.
Although ProcessOut connects directly to your PSPs to retrieve transactions for your automatically without any technical integration or change required from your side, it can sometimes still make sense to push transactions programmatically to our API. Such a case could for example be that the PSP doesn’t expose any API to retrieve transactions from and you as a merchant want data to be ingested in ProcessOut’s Analytics and Monitoring tools in real-time.
Pushing data
curl -X POST https://api.processout.com/handlers/ingest-transactions/gway_conf_9ie0prejnta3p9l2ns9030fiphlra7sz \
-u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_mah31RDFqcDxmaS7MvhDbJfDJvjtsFTB \
-H "Content-Type: application/json" \
-d @- << EOF
{
"transactions": [{
"id": "your-transaction-id",
"customer": {
"id": "your-customer-id",
"email": "john@smith.com",
"first_name": "John",
"last_name": "Smith",
"address1": "23 rue de Strasbourg",
"address2": "1e etage",
"city": "Paris",
"state": "",
"zip": "75001",
"country_code": "FR",
"ip_address": "127.0.0.1",
"metadata": {
"custom_field": "with whatever data you want"
},
"created_at": "2009-11-10T23:00:00Z"
},
"new_operation": {
"id": "your-operation-id",
"card": {
"id": "your-card-id",
"iin": "424242",
"last_4_digits": "4242",
"exp_month": 12,
"exp_year": 2020,
"name": "Cardholder name",
"metadata": {
"custom_field": "with whatever data you want"
},
"created_at": "2009-11-10T23:00:00Z"
},
"amount": "12.90",
"has_failed": false,
"type": "authorization",
"metadata": {
"custom_field": "with whatever data you want"
},
"raw_error_code": "05",
"raw_error_code_norm": "sips",
"payment_type": "card",
"acquirer_name": "societe generale",
"eci": "05",
"mcc": "5734",
"merchant_account_id": "your-merchant-id",
"cvc_check": "passed",
"avs_postal_check": "passwed",
"avs_street_check": "unavailable",
"avs_name_check": "unavailable",
"three_d_s_check": "passed",
"created_at": "2009-11-10T23:00:00Z"
},
"name": "Your transaction name/ID",
"currency": "EUR",
"metadata": {
"custom_field": "with whatever data you want"
},
"created_at": "2009-11-10T23:00:00Z"
}]
}
EOF
Pushing data to ProcessOut is done through one simple API endpoint. You can find a sample of the request JSON payload on the right side of the screen.
Don’t be afraid by the size of the JSON payload! Although it might appear lengthy (especially compared to our other routes), the required data is very straight-forward, and some of it is only optional when available.
Please note several things:
The URL contains the gateway configuration ID to which the transaction you’re pushing will be linked.
This means that if you’re using several PSPs, you’ll need to create one gateway configuration for each of them in order for us to accurately split the transactions between them;
The transaction amount isn’t stored in the transaction itself, but is dynamically computed from the operations you add to it. For example, a transaction
Many fields aren’t required, but it is always best to send as many as possible, as this is what gives Telescope data to work with.
Send raw error codes; not ones that you have potentially normalized on your side.
raw_error_code
should always contain the exact error code sent back by a PSP, andraw_error_code_norm
should contain the name of the PSP that generated it. We’ll take care of parsing it.
Transaction attributes
id string Required |
ID of the transaction you have stored internally. Should be unique |
name string Required |
Name of the transaction. For example, its bank statement dynamic descriptor |
currency string Required |
Currency of the transaction. For example, EUR or USD |
new_operation Operation Required |
New operation processed on this transaction (such as an authorization or a refund) |
customer Customer |
Customer object to which this transaction is linked. Not required, but strongly recommended if available |
metadata Metadata dictionary |
Context related to the transaction, key-value pair (string - string) |
created_at RFC1123 date or timestamp |
Date the transaction was created at |
Operation attributes
id string Required |
ID of the operation you have stored internally. Should be unique |
card Card Required if payment_type=card |
Card object, required if the payment_type is card |
type string Required |
Type of the operation. Can be authorization , capture , void , refund , chargeback |
amount string Required |
Amount of the operation, in the currency of the transaction. ex: "12.23" for an amount of 12.23 |
has_failed boolean Required |
true if the operation was failed (for example if an authorization was declined), false otherwise |
raw_error_code string Required if has_failed |
The raw error code returned by your PSP, such as 05 for SIPS. Do NOT send a modified error code, or we won’t be able to parse it |
raw_error_code_norm string Required if has_failed |
Norm of the error code (i.e. which kind of PSP generated that error code). Currently supported norms are french_bank , payline , sips , hipay . Contact us if yours isn’t listed |
payment_type string Required |
Type of the payment. Can be any of card , three-d-s , paypal , vpay , sepa , ideal , sofort , apple-pay , bancontact , android-pay |
acquirer_name string |
Acquirer used to process the transaction, such as societe generale |
merchant_account_id string |
ID of the merchant account used to process the transaction. Can be of any format |
eci string |
ECI used to process the transaction (also known as ERT in France). An example value is 05 for non-3DS transaction |
mcc string |
MCC (Merchant Category Code) used to process the transaction. An example value is 5734 for SaaS businesses |
cvc_check string |
Status of the CVC check, if known. Can be passed , failed , unavailable , unchecked , unknown , required . Unavailable means the CVC wasn’t available to be sent to the PSP, whereas unchecked means it was available but wasn’t used to process the check. Required means the CVC wasn’t available but was required by the bank to accept the transaction |
avs_postal_check string |
Status of the AVS postal check, if known. Contains the same type of value as cvc_check above |
three_d_s_check string |
Status of the 3DS check performed on the transaction, if any. Can be passed or failed . If left empty, it means the transaction wasn’t authenticated using 3DS |
metadata Metadata dictionary |
Context related to the operation, key-value pair (string - string) |
created_at RFC1123 date or timestamp |
Date the operation was created at |
Customer attributes
id string Required |
ID of the customer you have stored internally. Should be unique |
email string |
Email of the customer |
first_name string |
First name of the customer |
lasts_name string |
Last name of the customer |
address1 string |
Address line 1 of the customer |
address2 string |
Address line 2 (such as floor) of the customer, if any |
city string |
City of the customer |
state string |
State of the customer, if any |
zip string |
ZIP code of the customer |
country_code string |
Country code of the customer, such as FR for France |
ip_address string |
IP address of the customer |
metadata Metadata dictionary |
Context related to the operation, key-value pair (string - string) |
created_at RFC1123 date or timestamp |
Date the operation was created at |
Card attributes
id string Required |
ID of the card/token you have stored internally. Should be unique |
iin string Required |
IIN of the card. Also known as BIN, or the first 6 digits |
last_4_digits string |
Last 4 digits of the card, if available |
exp_month integer Required |
Expiry month of the card |
exp_year integer Required |
Expiry year of the card, 4 digits format (i.e. 2018 instead of 18) |
name string |
Cardholder name if one was used to submit the transaction |
metadata Metadata dictionary |
Context related to the operation, key-value pair (string - string) |
created_at RFC1123 date or timestamp |
Date the operation was created at |