NAV

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8 \
    --data-urlencode expand[]=subscriptions
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

customer = client.new_customer().find("cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb", {
    "expand": ["subscriptions"]
})
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

customer = client.customer.find("cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb", {
    expand: ["subscriptions"]
})
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$customer = $client->newCustomer()->find("cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb", array(
    "expand" => array("subscriptions")
));
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8 \
    --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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

customers = client.new_customer().all({
    "start_after": "cust_FM5ZDn3PjkCmDVXYnqrZFrnlypilDicD",
    "limit":       20,
    "order":       "asc"
})
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

customers = client.customer.all(
    start_after: "cust_FM5ZDn3PjkCmDVXYnqrZFrnlypilDicD",
    limit:       20,
    order:       "asc"
)
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$customers = $client->newCustomer()->all(array(
    "startAfter" => "cust_FM5ZDn3PjkCmDVXYnqrZFrnlypilDicD",
    "limit"      => 20,
    "order"      => "asc"
));
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

// Prefix project ID with `test-`
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

# Prefix project ID with `test-`
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

# Prefix project ID with `test-`
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

// Prefix project ID with `test-`
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

// 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 the payment modal or 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 expandable
Details about the invoice, in the form of a list of InvoiceDetail object- see below for object reference
name
string
Required
Name of the invoice/item to sell
statement_descriptor
string
Statement that will be shown on your customer’s bank account
amount
string
Required
Amount to be paid
currency
string
Required
Currency of the invoice, in the ISO 4217 format (ex: USD)
return_url
string
URL used to redirect the customer once the payment is placed
cancel_url
string
URL used to redirect the customer when the payment is canceled
metadata
Metadata
dictionary
Context related to the invoice, key-value pair (string - string)
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
type
string
Type of the invoice detail- can be a string containing anything (up to 30 characters)
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)

Create an invoice

curl -X POST https://api.processout.com/invoices \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8 \
    -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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$invoice = $client->newInvoice()->create(array(
    "customer_id"          => "cust_LvjCcLOVe6iWn2aeCNhNmK7RbbG6K8XF",
    "name"                 => "Amazing item",
    "statement_descriptor" => "amazing item",
    "amount"               => "4.99",
    "currency"              => "USD"
));
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

invoice = client.new_invoice().find("iv_MgeLS2Rr3ZGwjqOvDvYSuWx7ce88luXl")
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

invoice = client.invoice.find("iv_MgeLS2Rr3ZGwjqOvDvYSuWx7ce88luXl")
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$invoice = $client->newInvoice()->find("iv_MgeLS2Rr3ZGwjqOvDvYSuWx7ce88luXl");
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8 \
    -d source=card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

// 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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

# 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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

# The source could also be a token tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy
transaction = invoice.capture("card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ")
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

// The source could also be a token tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy
$transaction = $invoice->capture("card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ");
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

// 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.

Void an invoice

curl -X POST https://api.processout.com/invoices/iv_MgeLS2Rr3ZGwjqOvDvYSuWx7ce88luXl/void \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

// 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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

transaction = invoice.void()
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

transaction = invoice.void()
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$transaction = $invoice->void();
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

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.

3-D Secure

3-D Secure is a protocol developed by card schemes (such as Visa or Mastercard) to provide a way to better authenticate the buyer through its bank and improve the security of online payments. Its goal is to reduce fraud and improve the ratio of approved transactions.

Please note that not every card scheme is compatible with the 3-D Secure protocole, and even though a card could be compatible, it might not be enrolled in the 3-D Secure program.

Initiate a 3-D Secure flow

curl -X POST https://api.processout.com/invoices/iv_MgeLS2Rr3ZGwjqOvDvYSuWx7ce88luXl/three-d-s \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8 \
    -d source=card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

// The source could also be a token tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy
invoice.initiateThreeDS("card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ").then(
    function(customerAction) {
        // customerAction contains the `url` field where the customer
        // should be redirected

    }, function(err) {
        // The invoice could not be captured
    });
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

# The source could also be a token tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy
customer_action = invoice.initiate_three_d_s("card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ")
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

# The source could also be a token tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy
customer_action = invoice.initiate_three_d_s("card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ")
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

// The source could also be a token tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy
$customerAction = $invoice->initiateThreeDS("card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ");
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

// The source could also be a token tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy
custAction, _ := iv.InitiateThreeDS("card_1jSEVrx7oaRta1KEdxoMWbiGkK2MijrZ")

To initiate a 3-D Secure flow, you’ll first need to have a pending invoice ready. You’ll also need to either have a card or a customer token representing a card to initiate the 3DS authentication.

If the provided card is enrolled in a 3-D Secure program, a customer_action will be returned, of a type url and a value containing the link to which your customer should be redirected to.

Once redirected to the customer action URL, the customer will be able to authenticate on its bank. When the authentication is done, it is then redirected back to ProcessOut to verify the 3DS authentication. If you specified a return_url during the invoice creation, the customer will also be redirected back to this link so you can continue with the payment flow.

Capture a 3DS invoice

When a transaction is fully 3-D Secure authenticated, you can follow the same flow as usual, by calling either authorize or capture on the invoice to finish the payment.

Beware that when authorizing/capturing a previously 3-D Secure authenticated transaction you should use the same card that was used to initiate the 3-D Secure flow.

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
first_name
string
First name of the customer
last_name
string
Last name of the customer
address1
string
Primary address line of the customer
address2
string
Secondary address line of the customer
city
string
City of the customer
state
string
State of the customer
zip
string
ZIP code of the customer
phone_number
string
Phone number of the customer
legal_document
string
Legal document number. Required in some countries. (example for a CPF document in Brazil: 853.513.468-93)
country_code
string
Customer’s address country code (ex: US, FR)
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

Create a customer

curl -X POST https://api.processout.com/customers \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8 \
    -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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

customer = client.customer.create(
    email:      "john@smith.com",
    first_name: "John",
    last_name:  "Smith"
)
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$customer = $client->newCustomer()->create(array(
    "email"      => "john@smith.com",
    "first_name" => "John",
    "last_name"  => "Smith"
));
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

client.newCustomer().find("cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb").then(
    function(customer) {
        //
    }, function(err) {
        // An error occured
    });
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

customer = client.new_customer().find("cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb")
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

customer = client.customer.find("cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb")
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$customer = $client->newCustomer()->find("cust_UVYZP5I5741rFHQDEZXGLm777fCZzQAb");
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8 \
    -d first_name="New Name"
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

customer.setFirstName("New name");
customer.save();
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

customer.first_name = "New name"
customer.save()
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

customer.first_name = "New name"
customer.save
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$customer->setFirstName("New name");
$customer->save();
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

client.newCustomer({
    id: "cust_LvjCcLOVe6iWn2aeCNhNmK7RbbG6K8XF"
}).delete().then(
    function(ok) {
        //
    }, function() {});
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

customer = client.new_customer({
    "id": "cust_LvjCcLOVe6iWn2aeCNhNmK7RbbG6K8XF"
}).delete()
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

customer = client.customer(
    id: "cust_LvjCcLOVe6iWn2aeCNhNmK7RbbG6K8XF"
).delete
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$customer = $client->newCustomer(array(
    "id" => "cust_LvjCcLOVe6iWn2aeCNhNmK7RbbG6K8XF"
))->delete();
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

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
token
Token expandable
Token created using this card object, if any
scheme
string
Read-only
Scheme of the card, such as Visa or Mastercard
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
Read-only
Cardholder name
address1
string
Read-only
Cardholder primary address line
address2
string
Read-only
Cardholder secondary address line
city
string
Read-only
Cardholder city
state
string
Read-only
Cardholder state
country_code
string
Read-only
Cardholder country
zip
string
Read-only
Cardholder zip
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

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
type
string
Read-only
Source used to create the token. Most of the time will be a card
is_subscription_only
boolean
Read-only
Whether or not the token was created for a specific subscription
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

Create a token

curl -X POST https://api.processout.com/customers/cust_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj/tokens \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8 \
    -d source=card_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

token = client.new_token().create({
    "customer_id": "cust_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj",
    "source":      "card_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj"
})
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

token = client.token.create(
    customer_id: "cust_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj",
    source:      "card_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj"
)
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$token = $client->newToken()->create(array(
    "customer_id" => "cust_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj",
    "source"      => "card_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj"
));
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

token = client.new_token().find("cust_WtaVdUjAGpOlbLiYWYXBR67whr91Rlks",
    "tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy")
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

token = client.token.find("cust_WtaVdUjAGpOlbLiYWYXBR67whr91Rlks",
    "tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy")
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$token = $client->newToken()->find("cust_WtaVdUjAGpOlbLiYWYXBR67whr91Rlks",
    "tok_fKK4btSG7wd13ZZaevzhMcuNbpjcu1Zy");
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

tokens = customer.fetch_tokens()
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

tokens = customer.fetch_tokens()
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$tokens = $customer->fetchTokens();
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8
token.delete().then(
    function(ok) {
        // 

    }, function(err) {
        // The token could not be deleted
    });
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

token.delete()
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

token.delete
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$token->delete();
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

tok.Delete()

Deleting a token is irreversible and cannot be undone. An error is thrown if the token could not be deleted.

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
Card expandable
Card used to capture 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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

transaction = client.new_transaction().find("tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC")
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

transaction = client.transaction.find("tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC")
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$transaction = $client->newTransaction()->find("tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC");
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

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.

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

Issue a refund

curl -X POST https://api.processout.com/transactions/tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC/refunds \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8 \
    -d reason=customer_request \
    -d amount=4.99
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

refund = client.refund.create(
    transaction_id: "tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC",
    reason:         "customer_request",
    amount:         "4.99"
)
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$refund = $client->newRefund()->create(array(
    "transaction_id" => "tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC",
    "reason"         => "customer_request",
    "amount"         => "4.99"
));
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

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.

Fetch a refund

curl -X GET https://api.processout.com/transactions/tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC/refunds/refd_QKliea9OGXtLBXcar2SJjfD11aY0J2SH \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

refund = client.new_refund().find("tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC",
    "refd_QKliea9OGXtLBXcar2SJjfD11aY0J2SH")
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

refund = client.refund.find("tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC",
    "refd_QKliea9OGXtLBXcar2SJjfD11aY0J2SH")
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$refund = $client->newRefund()->find("tr_ItJdKlhfaVn0SUGd9z1i9Jqe0STl4jxC",
    "refd_QKliea9OGXtLBXcar2SJjfD11aY0J2SH");
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

event = client.new_event().find("ev_T3wg9169RyGLnf1BIgTjLhrolEZU1DSb")
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

event = client.event.find("ev_T3wg9169RyGLnf1BIgTjLhrolEZU1DSb")
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$event = $client->newEvent()->find("ev_T3wg9169RyGLnf1BIgTjLhrolEZU1DSb");
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

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.adjusted
The transaction was adjusted by your payment provider (such as refunds on payment fees with credits)

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

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 endpoints 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.

Usage

# Webhooks are not supported with cURL.
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

// 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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")


# 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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")


# 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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$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 "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

// 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 (beta)

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 this feature is currently in Beta. 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 mexpandable
Items listed in the payout
status
string
Read-only
Status of the payout. Can be pending, in-flight, received, canceled or failed
failure_reason_code
string
Read-only
Failure reason code (if status is set to failed)
failure_reason
string
Read-only
Failure reason message (if status is set to 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 wire was issued
bank_summary
string
Read-only
Bank summary of the wire
sales_transactions
integer
Read-only
Number of transactions known by ProcessOut involved in this wire
sales_volume
string
Read-only
Transactions volume known by ProcessOut involved in this wire
refunds_transactions
integer
Read-only
Number of refunds known by ProcessOut involved in this wire
refunds_volume
string
Read-only
Refunds volume known by ProcessOut involved in this wire
chargebacks_transactions
integer
Read-only
Number of chargebacks known by ProcessOut involved in this wire
chargebacks_volume
string
Read-only
Chargebacks volume known by ProcessOut involved in this wire
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 wired 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
type
string
Read-only
Type of the payout item. Can be sale, refund, chargeback, fee, adjustment, reserve
gateway_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)
fee
string
Read-only
Fee taken on this specific payout item
metadata
Metadata
dictionary
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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8
// Javascript is currently not supported for Payouts
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

# Python is currently not supported for Payouts
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

# Ruby is currently not supported for Payouts
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

// PHP is currently not supported for Payouts
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

// 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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8
// Javascript is currently not supported for Payouts
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

# Python is currently not supported for Payouts
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

# Ruby is currently not supported for Payouts
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

// PHP is currently not supported for Payouts
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

// Go is currently not supported for Payouts

Paginate through all the items of a specific payout.

Recurring payments

Recurring payments

ProcessOut makes it easy to automatically bill your customers periodically.

Payment gateways are abstracted in such a way that you only need to create a subscription resource to make your customer go through the authorization, and ProcessOut will handle all the payment methods and the subscription life cycle.

Learn more about it in our guide.

Plans

Plans can be seen as templates for your subscriptions.

Attributes
id
string
Required
ID of the plan. Must be unique to the project
name
string
Required
Name of the plan
amount
string
Required
Amount to be paid at every iteration of the subscription
currency
string
Required
Currency of the subscription, in the ISO 4217 format (ex: USD)
interval
string
Required
Interval between each subscription iteration. “1m” for monthly subscriptions, “1w” for weekly.
trial_period
string
Trial period. “1w” for one week, “3m” for three months.
metadata
Metadata
dictionary
Context related to the plan, key-value pair (string - string)
sandbox
boolean
Read-only
created_at
RFC1123 date or timestamp
Read-only

Create a plan

curl -X POST https://api.processout.com/plans \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8 \
    -d id="silver-plan" \
    -d name="Amazing item" \
    -d amount="4.99" \
    -d currency=USD \
    -d interval=1m
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

client.new_plan().create({
    id:       "silver-plan",
    name:     "Amazing item",
    amount:   "4.99",
    currency: "USD",
    interval: "1m"
}).then(function(plan) {
    // 

}, function(err) {
    // An error occured

});
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

plan = client.new_plan().create({
    "id":       "silver-plan",
    "name":     "Amazing item",
    "amount":   "4.99",
    "currency": "USD",
    "interval": "1m"
})
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

plan = client.plan.create(
    id:       "silver-plan",
    name:     "Amazing item",
    amount:   "4.99",
    currency: "USD",
    interval: "1m"
)
<?php
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$plan = $client->newPlan()->create(array(
    "id"       => "silver-plan",
    "name"     => "Amazing item",
    "amount"   => "4.99",
    "currency" => "USD",
    "interval" => "1m"
));
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

plan, err := client.NewPlan().Create(processout.PlanCreateParameters{
    Plan: &processout.Plan{
        ID:       processout.String("silver-plan"),
        Name:     processout.String("Amazing item"),
        Amount:   processout.String("4.99"),
        Currency: processout.String("USD"),
        Interval: processout.String("1m"),
    },
})

Create a plan with the given attributes.

Fetch a plan

curl -X GET https://api.processout.com/plans/silver-plan \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

client.newPlan().find("silver-plan").then(
    function(plan) {
        // 

    }, function(err) {
        // An error occured

    });
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

plan = client.new_plan().find("silver-plan")
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

plan = client.plan.find("silver-plan")
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$plan = $client->newPlan()->find("silver-plan");
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

plan, err := client.NewPlan().Find("silver-plan")

Fetch a plan from its ID. Throws an error if the plan could not be found.

Delete a plan

curl -X DELETE https://api.processout.com/plans/silver-plan \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

client.newPlan({
    id: "silver-plan"
}).delete().then(function(success) {
        // 

    }, function(err) {
        // Could not delete it

    });
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

client.new_plan({
    "id": "silver-plan"
}).delete()
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

client.plan(
    id: "silver-plan"
).delete
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$client->newPlan(array(
    "id": "silver-plan"
))->delete();
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

err := client.NewPlan(&processout.Plan{
    ID: processout.String("silver-plan"),
}).Delete()

Deletes a plan. An error is thrown if the plan could not be deleted.

Subscriptions

Subscriptions are objects representing your customers’ subscriptions.

Attributes
id
string
Read-only
url
string
Read-only
url to the ProcessOut checkout page
customer
customer_id
Customer expandable
Customer owning the subscription
plan
plan_id
Plan expandable
Plan, if one was used when creating the subscription
token
token_id
Token expandable
Token used to capture payments of the subscription
discounts
list of Discounts expandable
Discounts list applied to the subscription
addons
list of Addons expandable
Addons list applied to the subscription
name
string
Name of the subscription
amount
string
Base amount of the subscription
billable_amount
string
Amount to be paid at the next subscirption billing cycle (computed from discounts and addons)
discounted_amount
string
Amount currently discounted on the subscription
addons_amount
string
Amount currently added to the subscription with addons
currency
string
Currency of the subscription, in the ISO 4217 format (ex: USD)
interval
string
Interval between each subscription iteration. “1m” for monthly subscriptions, “1w” for weekly.
return_url
string
url used to redirect the customer once the payment is placed
cancel_url
string
url used to redirect the customer when the payment is canceled
trial_end_at
RFC1123 date or timestamp
Date at which the trial of the subscription will end. Defaults to no trial
cancel_at
RFC1123 date or timestamp
Date at which you want to automatically cancel the subscription. Is automatically set the current time when canceling a subscription to trigger an immediate cancellation
canceled
boolean
cancellation_reason
boolean
If canceled is true, represents the reason why the subscription was canceled
pending_cancellation
boolean
Whether or not the subscription is pending cancellation (meaning a cancel_at date was set)
unpaid_state
string
When the subscription has unpaid invoices, defines the dunning logic of the subscription (as specified in the project settings)
metadata
Metadata
dictionary
Context related to the subscription, key-value pair (string - string)
sandbox
boolean
Read-only
created_at
RFC1123 date or timestamp
Read-only
Date at which the subscription was created
activated_at
RFC1123 date or timestamp
Read-only
Date at which the subscription was activated
iterate_at
RFC1123 date or timestamp
Read-only
Date at which the subscription will iterate, corresponding to the next billing cycle

Create a subscription

curl -X POST https://api.processout.com/subscriptions \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8 \
    -d customer_id=cust_uYW5WVnjHe91qnsUA1sHOxEjdAySvg0P \
    -d name="Amazing item" \
    -d amount="4.99" \
    -d currency=USD \
    -d interval=1m
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

var subscription = client.newSubscription().create({
    customer_id: "cust_uYW5WVnjHe91qnsUA1sHOxEjdAySvg0P",

    name:     "Amazing subscription",
    amount:   "4.99",
    currency: "USD",
    interval: "1m"
}).then(function(subscription) {
    // 

}, function(err) {
    // An error occured

});

// or
var subscription = client.newSubscription().create({
    customer_id: "cust_uYW5WVnjHe91qnsUA1sHOxEjdAySvg0P",
    plan_id:     "silver-plan"
}).then(function(subscription) {
    // 

}, function(err) {
    // An error occured

});
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

subscription = client.new_subscription().create({
    "customer_id": "cust_uYW5WVnjHe91qnsUA1sHOxEjdAySvg0P",

    "name":     "Amazing subscription",
    "amount":   "4.99",
    "currency": "USD",
    "interval": "1m"
})

# or
subscription = client.new_subscription().create({
    "customer_id": "cust_uYW5WVnjHe91qnsUA1sHOxEjdAySvg0P",
    "plan_id":     "silver-plan"
})
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

subscription = client.subscription.create(
    customer_id: "cust_uYW5WVnjHe91qnsUA1sHOxEjdAySvg0P",

    name:     "Amazing subscription",
    amount:   "4.99",
    currency: "USD",
    interval: "1m"
)

# or
subscription = client.subscription.new().create(
    customer_id: "cust_uYW5WVnjHe91qnsUA1sHOxEjdAySvg0P",
    plan_id:     "silver-plan"
)
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$subscription = $client->newSubscription()->create(array(
    "customer_id" => "cust_uYW5WVnjHe91qnsUA1sHOxEjdAySvg0P",

    "name":    => "Amazing subscription",
    "amount"   => "4.99",
    "currency" => "USD",
    "interval" => "1m"
));

// or
$subscription = $client->newSubscription()->create(array(
    "customer_id" => "cust_uYW5WVnjHe91qnsUA1sHOxEjdAySvg0P",
    "plan_id"     => "silver-plan"
));
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

sub, err := client.NewSubscription().Create(processout.SubscriptionCreateParameters{
    Subscription: &processout.Subscription{
        CustomerID: processout.String("cust_uYW5WVnjHe91qnsUA1sHOxEjdAySvg0P"),
        Name:       processout.String("Amazing item"),
        Amount:     processout.String("4.99"),
        Currency:   processout.String("USD"),
        Interval:   processout.String("1m"),
    },
})

// or
sub, err := client.NewSubscription().Create(&processout.SubscriptionCreateParameters{
    Subscription: &processout.Subscription{
        CustomerID: "cust_uYW5WVnjHe91qnsUA1sHOxEjdAySvg0P",
        PlanID:     "silver-plan",
    },
})

To create a subscription for a specific customer, the field interval must be set. To make it easy to define precise subscription intervals, interval is a signed sequence of decimal numbers, such as “1m”, “2w” or “1m15d”. Valid time units are “d” for days, “w” for weeks, “m” for months and “y” for years. interval must represent a positive number of days.

The field trial_end_at may also be set to a specific date to add a trial to the subscription, during which the customer will not be charged. The trial will end at that specific date automatically.

Fetch a subscription

curl -X GET https://api.processout.com/subscriptions/sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3 \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

client.newSubscription().find("sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3").then(
    function(subscription) {
        // 

    }, function(err) {
        // An error occured

    });
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

subscription = client.new_subscription().find("sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3")
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

subscription = client.subscription.find("sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3")
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$subscription = $client->newSubscription()->find("sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3");
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

sub, err := client.NewSubscription().Find("sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3")

Fetch a subscription from its ID. Throws an error if the subscription could not be found.

Activate a subscription

curl -X PUT https://api.processout.com/subscriptions/sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3 \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8 \
    -d source=card_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

client.newSubscription().save({
    id:     "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    source: "card_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj"
}).then(
    function(subscription) {
        // 

    }, function(err) {
        // An error occured
    });
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

subscription = client.new_subscription().save({
    "id":     "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    "source": "card_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj"
})
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

subscription = client.subscription().save(
    id:     "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    source: "card_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj"
)
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$subscription = $client->newSubscription()->save(array(
    "id"     => "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    "source" => "card_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj"
));
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

sub, err := client.NewSubscription().ApplySource(processout.SubscriptionSaveParameters{
    Subscription: &processout.Subscription{
        ID: processout.String("sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3"),
    },
    Source: "card_C4hZXQTU0aWoYeenHYC0DektYDqf8ocj",
})

Activating a subscription is done by applying a source to the subscription. The source can be a card, a Token or a Gateway Request. An error is thrown if the source could not be used.

Update a subscription

curl -X PUT https://api.processout.com/subscriptions/sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3 \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8 \
    -d plan_id="gold-plan" \
    -d prorate=true
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

client.newSubscription().save({
    id:      "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    plan_id: "gold-plan",
    prorate: true
}).then(
    function(subscription) {
        // 

    }, function(err) {
        // An error occured
    });
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

subscription = client.new_subscription().save({
    "id":      "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    "plan_id": "gold-plan",
    "prorate": true
})
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

subscription = client.subscription().save(
    id:      "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    plan_id: "gold-plan",
    prorate: true
)
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$subscription = $client->newSubscription()->save(array(
    "id"      => "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    "plan_id" => "gold-plan",
    "prorate" => true
));
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

sub, err := client.NewSubscription().Save(processout.SubscriptionSaveParameters{
    Subscription: &processout.Subscription{
        ID:     processout.String("sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3"),
        PlanID: processout.String("gold-plan"),
    },
    Prorate: true,   
})

A subscription plan can be changed to upgrade/downgrade the subscription.

A prorate field is also available to define whether or not you want to enable proration. Learn more about proration here ↗.

Cancel a subscription

curl -X DELETE https://api.processout.com/subscriptions/sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3 \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8 \
    -d cancel_at="2022-10-02T15:00:00Z" \
    -d cancellation_reason="Cancellation reason"
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

client.newSubscription().cancel({
    id: "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    cancellation_reason: "Cancellation reason",
    cancel_at:           "2022-10-02T15:00:00Z",
}).then(function(subscription) {
    //

}, function(err) {
    // Could not cancel it

});
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

subscription = client.new_subscription().cancel({
    "id": "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    "cancellation_reason": "Cancellation reason",
    "cancel_at":           "2022-10-02T15:00:00Z"
})
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

subscription = client.subscription().cancel(
    id: "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    cancellation_reason: "Cancellation reason",
    cancel_at:           "2022-10-02T15:00:00Z"
)
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$subscription = $client->newSubscription()->cancel(array(
    "id": "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    "cancellation_reason" => "Cancellation reason",
    "cancel_at"           => "2022-10-02T15:00:00Z"
));
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

sub, err := client.NewSubscription().Cancel(processout.SubscriptionCancelParameters{
    Subscription: &processout.Subscription{
        ID: processout.String("sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3"),
        CancellationReason: processout.String("Cancellation reason"),
        CancelAt:           processout.Time(time.Now()),
    },
)

A subscription can be cancelled immediately or at a certain date. A short reason for the cancellation may also be provided. An error is thrown if the cancellation couldn’t be done.

When doing an immediate cancellation, ProcessOut internally stores a date for the cancellation date in the past so that our worker pulls the job as soon as possible.

Coupons

Coupons can be seen as templates for subscription discounts.

Attributes
id
string
Required
ID of the coupon. Must be unique to the project
amount_off
string
Required if percent_off is null
Amount to be discounted from the subscription
percent_off
integer
Required if amount_off is null
Percentage of the subscription amount to be discounted. Ex: 25
currency
string
Required if amount_off is set
Currency of the coupon, in the ISO 4217 format (ex: USD)
iteration_count
integer
Number of iteration of the subscription the coupon will last. 3 on a monthly subscription will make the coupon last 3 months. 0 makes the coupon last forever
max_redemptions
integer
Maximum number of times a coupon can be redeemed (ie applied on a subscription) by your customers before expiring
expires_at
string
Date at which the coupon will automatically expire
metadata
Metadata
dictionary
Context related to the coupon, key-value pair (string - string)
sandbox
boolean
Read-only

Create a coupon

curl -X POST https://api.processout.com/coupons \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8 \
    -d id="25percentoff" \
    -d percent_off=25
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

var coupon = client.newCoupon().create({
    id:          "25percentoff",
    percent_off: 25
}).then(
    function(coupon) {
        // 

    }, function(err) {
        // An error occured
    });
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

coupon = client.new_coupon().create({
    "id":          "25percentoff",
    "percent_off": 25
})
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

coupon = client.coupon.create(
    id:          "25percentoff",
    percent_off: 25
)
<?php
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$coupon = $client->newCoupon()->create(array(
    "id"          => "25percentoff",
    "percent_off" => 25
));
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

coupon, err := client.NewCoupon().Create(processout.CouponCreateParameters{
    Coupon: &processout.Coupon{
        ID:         processout.String("25percentoff"),
        PercentOff: processout.Int64(25),
    },
})

Create a coupon with the given attributes.

Once a coupon is create, you can use it to create a discount.

Fetch a coupon

curl -X GET https://api.processout.com/coupons/25percentoff \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

client.newCoupon().find("25percentoff").then(
    function(coupon) {
        // 

    }, function(err) {
        // An error occured

    });
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

coupon = client.new_coupon().find("25percentoff")
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

coupon = client.coupon.find("25percentoff")
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$coupon = $client->newCoupon()->find("25percentoff");
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

coupon, err := client.NewCoupon().Find("25percentoff")

Fetch a coupon from its ID. Throws an error if the coupon could not be found.

Delete a coupon

curl -X DELETE https://api.processout.com/coupons/25percentoff \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

client.newCoupon({
    id: "25percentoff"
}).delete("25percentoff").then(function(ok) {
        // 

    }, function(err) {
        // An error occured

    });
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

client.new_coupon({
    "id": "25percentoff"
}).delete()
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

client.coupon(
    id: "25percentoff"
).delete
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$client->newCoupon(array(
    "id" => "25percentof"
))->delete();
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

err = client.NewCoupon(&processout.Coupon{
    ID: processout.String("25percentoff"),
}).Delete()

Deletes a plan. An error is thrown if the plan could not be deleted.

Discounts

Discount objects represent discounts applied to your customers’ subscriptions.

Attributes
id
string
subscription
subscription_id
Subscription expandable
Subscription on which the discount was applied
coupon
coupon_id
Coupon expandable
Coupon used to generate the discount
amount
string
Required
Amount discounted from the subscription
expires_at
string
Date at which the coupon will automatically expire
metadata
Metadata
dictionary
Context related to the subscription, key-value pair (string - string)
sandbox
boolean
Read-only

Apply a discount

curl -X POST https://api.processout.com/subscriptions/sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3/discounts \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8 \
    -d amount=5

# or
curl -X POST https://api.processout.com/subscriptions/sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3/discounts \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8 \
    -d coupon_id=25percentoff
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

client.newDiscount().apply({
    subscription_id: "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    amount:          "5"
}).then(
    function(discount) {
        // 

    }, function(err) {
        // An error occured
    });

// or
client.newDiscount().create({
    subscription_id: "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    coupon_id:       "25percentoff"
});
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

discount = client.new_discount().apply({
    "subscription_id": "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    "amount":          "5"
})

# or 
discount = client.new_discount().create({
    "subscription_id": "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    "coupon_id":       "25percentoff"
})
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

discount = client.discount.apply(
    subscription_id: "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    amount:          "5"
)

# or
discount = client.discount.new().create(
    subscription_id: "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    coupon_id:       "25percentoff"
)
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$discount = $client->newDiscount()->apply(array(
    "subscription_id" => "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    "amount"          => "5"
));

// or
$discount = $client->newDiscount()->create(array(
    "subscription_id" => "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    "coupon_id"       => "25percentoff"
));
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

discount, err := client.NewDiscount().Apply(processout.DiscountCreateParameters{
    Discount: &processout.Discount{
        SubscriptionID: processout.String("sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3"),
        Amount:         processout.Int64(5),
    }})

// or 
discount, err := client.NewDiscount().Create(processout.DiscountCreateParameters{
    Discount: &processout.Discount{
        SubscriptionID: "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
        CouponID:       "25percentoff",
    }})

Apply a discount for a subscription with the given attributes.

It is also possible to apply a coupon to a subscription.

Fetch a discount

curl -X GET https://api.processout.com/subscriptions/sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3/discounts/disc_F9NXdvflVDyE3KOz2qxLw0e31eBeLcDq \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

client.newDiscount().find("sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    "disc_F9NXdvflVDyE3KOz2qxLw0e31eBeLcDq").then(
        function(discount) {
            // 

        }, function(err) {
            // An error occured

        });
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

discount = client.new_discount().find("sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    "disc_F9NXdvflVDyE3KOz2qxLw0e31eBeLcDq")
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

discount = client.discount.find("sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    "disc_F9NXdvflVDyE3KOz2qxLw0e31eBeLcDq")
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$discount = $client->newDiscount()->find("sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    "disc_F9NXdvflVDyE3KOz2qxLw0e31eBeLcDq");
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

discount, err := client.NewDiscount().Find("sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    "disc_F9NXdvflVDyE3KOz2qxLw0e31eBeLcDq")

Fetch a discount from its ID and subscription. Throws an error if the discount could not be found.

Delete a discount

curl -X DELETE https://api.processout.com/subscriptions/sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3/discounts/disc_F9NXdvflVDyE3KOz2qxLw0e31eBeLcDq \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

client.newDiscount({
    subscription_id: "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    id:              "disc_F9NXdvflVDyE3KOz2qxLw0e31eBeLcDq"
}).delete().then(function(success) {
    // 

}, function(err) {
    // Could not delete it

});
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

client.new_discount({
    "subscription_id": "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    "id":              "disc_F9NXdvflVDyE3KOz2qxLw0e31eBeLcDq"
}).delete()
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

client.discount(
    subscription_id: "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    id:              "disc_F9NXdvflVDyE3KOz2qxLw0e31eBeLcDq"
).delete
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$client->newDiscount(array(
    "subscription_id" => "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    "id"              => "disc_F9NXdvflVDyE3KOz2qxLw0e31eBeLcDq"
))->delete();
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

err := client.NewDiscount(&processout.Discount{
    SubscriptionID: processout.String("sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3"),
    ID:             processout.String("disc_F9NXdvflVDyE3KOz2qxLw0e31eBeLcDq"),
}).Delete()

Removes a discount from a subscription. An error is thrown if the discount could not be removed.

Addons

Addons objects represent addons applied to your customers’ subscriptions.

Addons are additional billable objects that’ll be used to compute billed at each subscription cycle. Such addon could be used for:

  • Billing per user using your service
  • Billing for additional features
  • Billing for metered usage of your service (such as number of API calls)
Attributes
id
string
subscription
subscription_id
Subscription expandable
Subscription on which the addon was applied
plan
plan_id
Plan expandable
Plan used to generate the addon
name
string
Required
Name of the addon
type
string
Type of the addon, either recurring or metered. Defaults to recurring
amount
string
Required
Amount of the addon billed at each cycle
quantity
integer
Multiplier for the addon price. Defaults to 1, must be greater or equal to 0
metadata
Metadata
dictionary
Context related to the subscription, key-value pair (string - string)
sandbox
boolean
Read-only

Apply an addon

curl -X POST https://api.processout.com/subscriptions/sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3/addons \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8 \
    -d name="Addon name" \
    -d amount="5.00" \
    -d quantity=1 \
    -d type=metered \
    -d prorate=true

# or 
curl -X POST https://api.processout.com/subscriptions/sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3/addons \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8 \
    -d plan_id="addon-per-api-call" \
    -d type=metered \
    -d prorate=true
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

client.newAddon().create({
    subscription_id: "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",

    name:     "Addon name",
    amount:   "5.00",
    quantity: 1,
    type:     "metered",

    prorate: true
}).then(
    function(addon) {
        // 

    }, function(err) {
        // An error occured
    });

// or 
client.newAddon().create({
    subscription_id: "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",

    plan_id: "addon-per-api-call",
    type:    "metered",

    prorate: true
});
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

addon = client.new_addon().create({
    "subscription_id": "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",

    "name":     "Addon name",
    "amount":   "5.00",
    "quantity": 1,
    "type":     "metered",

    "prorate": true
})

# or 
addon = client.new_addon().create({
    "subscription_id": "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",

    "plan_id": "addon-per-api-call",
    "type":    "metered",

    "prorate": true
})
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

addon = client.addon.create(
    subscription_id: "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",

    name:     "Addon name",
    amount:   "5.00",
    quantity: 1,
    type:     "metered",

    prorate: true
)

# or 
addon = client.addon.new().create(
    subscription_id: "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",

    plan_id: "addon-per-api-call",
    type:    "metered",

    prorate: true
)
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$addon = $client->newAddon()->create(array(
    "subscription_id" => "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",

    "name"     => "Addon name",
    "amount"   => "5.00",
    "quantity" => 1,
    "type"     => "metered",

    "prorate" => true
));

// or 
$addon = $client->newAddon()->create(array(
    "subscription_id" => "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",

    "plan_id" => "addon-per-api-call",
    "type"    => "metered",

    "prorate" => true
));
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

addon, err := client.NewAddon().Create(processout.AddonApplyParameters{
    Addon: &processout.Addon{
        SubscriptionID: processout.String("sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3"),

        Name:     processout.String("Addon name"),
        Amount:   processout.String("5.00"),
        Quantity: processout.Int64(1),
        Type:     processout.String("metered"),
    },
    Prorate: true,
})

# or
addon, err := client.NewAddon().Create(&processout.AddonApplyParameters{
    Addon: &processout.Addon{
        SubscriptionID: "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",

        PlanID: "addon-per-api-call",
        Type:   "metered",
    },
    Prorate: true,
})

Apply an addon for a subscription with the given attributes.

It’s also possible to create an addon from an existing Plan.

It is possible to prorate the addon application by setting prorate to true. Learn more about proration here ↗.

Fetch an addon

curl -X GET https://api.processout.com/subscriptions/sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3/addons/addon_F9NXdvflVDyE3KOz2qxLw0e31eBeLcDq \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

client.newAddon().find("sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    "addon_F9NXdvflVDyE3KOz2qxLw0e31eBeLcDq").then(
        function(addon) {
            // 

        }, function(err) {
            // An error occured

        });
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

addon = client.new_addon().find("sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    "addon_F9NXdvflVDyE3KOz2qxLw0e31eBeLcDq")
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

addon = client.addon.find("sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    "addon_F9NXdvflVDyE3KOz2qxLw0e31eBeLcDq")
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$addon = $client->newAddon()->find("sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    "addon_F9NXdvflVDyE3KOz2qxLw0e31eBeLcDq");
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

addon, err := client.NewAddon().Find("sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    "addon_F9NXdvflVDyE3KOz2qxLw0e31eBeLcDq")

Fetch an addon from its ID and subscription. Throws an error if the addon could not be found.

Update an addon

curl -X PUT https://api.processout.com/subscriptions/sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3/addons/addon_F9NXdvflVDyE3KOz2qxLw0e31eBeLcDq \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8 \
    quantity=10 \
    prorate=true
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

addon.setQuantity(10)
addon.save({
    prorate: true
}).then(function(addon) {
    // 

}, function(err) {
    // An error occured

});

// or
addon.save({
    increment_quantity_by: 1,
    prorate:               true
});
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

addon.quantity = 10
addon.save({
    "prorate": true
})

# or
addon.save({
    "increment_quantity_by": 1,
    "prorate":               true
})
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

addon.quantity = 10
addon.save(
    prorate: true
)

#or
addon.save(
    increment_quantity_by: 1,
    prorate:               true
)
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$addon->setQuantity(10);
$addon->save(array(
    "prorate" => true
));

// or
$addon->save(array(
    "increment_quantity_by" => 1,
    "prorate"               => true
));
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

addon.Quantity = 10
_, err := addon.Save(processout.AddonSaveParameters{
    Prorate: true,
})

// or
_, err := addon.Save(processout.AddonSaveParameters{
    IncrementQuantityBy: 1,
    Prorate:             true,
})

Update an addon. Currently, only updating the quantity of an addon is possible.

The quantity of an addon can also be incremented, which removes the need to store the quantity on your side. This is especially useful when dealing with metered addons: you can update the addon at each API call made to your service for example, and increment the quantity by 1.

Delete an addon

curl -X DELETE https://api.processout.com/subscriptions/sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3/addons/addon_F9NXdvflVDyE3KOz2qxLw0e31eBeLcDq \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8 \
    -d prorate=true
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

client.newAddon({
    subscription_id: "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    id:              "addon_F9NXdvflVDyE3KOz2qxLw0e31eBeLcDq"
}).delete({
        prorate: true
}).then(
    function(success) {
            // 

    }, function(err) {
        // Could not delete it

    });
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

client.new_addon({
    "subscription_id": "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    "id":              "addon_F9NXdvflVDyE3KOz2qxLw0e31eBeLcDq"
}).delete({
    "prorate": true
})
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

client.addon(
    subscription_id: "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    id:              "addon_F9NXdvflVDyE3KOz2qxLw0e31eBeLcDq"
).delete(
    prorate: true
)
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$client->newAddon(array(
    subscription_id => "sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3",
    id              => "addon_F9NXdvflVDyE3KOz2qxLw0e31eBeLcDq"
))->delete(array(
    "prorate" => true
));
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

err := client.NewAddon(&processout.Addon{
    SubscriptionID: processout.String("sub_7kAxfNML6jIc3bltGIt0uK2nKHDyzzq3"),
    ID:             processout.String("addon_F9NXdvflVDyE3KOz2qxLw0e31eBeLcDq"),
}).Delete(processout.AddonDeleteParameters{
    Prorate: true,
})

Delete an addon from a subscription. An error is thrown if the addon could not be removed.

It is possible to prorate the addon deletion by setting prorate to true. Learn more about proration here ↗.

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_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8 \
    -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, and raw_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 recommanded 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
>_