NAV Navbar
Logo

Overview

Production Request

curl https://api.payload.co \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE:
import payload as pl
pl.api_key = 'secret_key_3bW9JMZtPVDOfFNzwRdfE'
require 'payload'
Payload.api_key = 'secret_key_3bW9JMZtPVDOfFNzwRdfE'
<?php
require_once('vendor/autoload.php');
Payload\Payload::$api_key = 'secret_key_3bW9JMZtPVDOfFNzwRdfE'
?>
var pl = require('payload-api');
pl.api_key = 'secret_key_3bW9JMZtPVDOfFNzwRdfE'
using Payload;
pl.api_key = "secret_key_3bW9JMZtPVDOfFNzwRdfE";

Test Request

curl https://api.payload.co \
    -u test_secret_key_dwjVajaCQKO4RJuV:
import payload as pl
pl.api_key = 'test_secret_key_dwjVajaCQKO4RJuV'
require 'payload'
Payload.api_key = 'test_secret_key_dwjVajaCQKO4RJuV'
<?php
require_once('vendor/autoload.php');
Payload\Payload::$api_url = 'test_secret_key_dwjVajaCQKO4RJuV';
?>
var pl = require('payload-api');
pl.api_key = 'test_secret_key_dwjVajaCQKO4RJuV'
using Payload;
pl.api_key = "test_secret_key_dwjVajaCQKO4RJuV";

Payload’s APIs use a RESTful API design with enhanced features like hierarchical object design and API Relational Model wrappers. You can explore the architecture in the API Design section.

API Architecture

Payment Stack

Install Packages

To use one of our language-specific API packages, select one of the following for instructions:

pip install payload-api

gem 'payload-api', '~> 0.5.6'

gem install payload-api

composer require payload/payload-api

npm install payload-api

nuget install payload-api

Test Environment

Test API Keys

You’ll find a set of production and test API keys in your dashboard. The test API keys give you access to a private test API environment where you can run simulated API requests to test and integrate Payload into your application. The test API keys start with test_secret_key and test_client_key.

Test Dashboard Access

To switch your dashboard to the test environment and access, manage, and review your test data, there is a toggle on the sidebar to switch between environments.


API Design

Payload’s API design incorporates a variety of concepts to create a simple, robust, and intuitive platform. The following sections will take you through the general API design concepts inherited in all of our API components.

Authentication

# Curl supports HTTP basic authentication with the `-u` command
# To use the `-u` command, add a `:` onto the API key.
curl "https://api.payload.co/transactions" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE:
import payload as pl
pl.api_key = 'secret_key_3bW9JMZtPVDOfFNzwRdfE'
require "payload"
Payload.api_key = "secret_key_3bW9JMZtPVDOfFNzwRdfE"
<?php
require_once('vendor/autoload.php');
Payload\Payload::$api_key = "secret_key_3bW9JMZtPVDOfFNzwRdfE";
?>
var pl = require('payload-api')
pl.api_key = 'secret_key_3bW9JMZtPVDOfFNzwRdfE'
using Payload;
pl.api_key = "secret_key_3bW9JMZtPVDOfFNzwRdfE";

Authentication with Payload uses a simple API secret key. The secret key is passed as the username field in an HTTP Basic Auth header. Your secret key is available from your dashboard in the API Keys section under settings.

Operations

Below are the HTTP methods for performing operations on the API objects. Operations can be executed on a single or list of known objects by their object id, or a group of objects based on query parameters by using Conditional Queries.

Method Description Example
GET Select one or many objects GET /transactions
POST Create one or many objects POST /transactions
PUT Update one or many objects PUT /transactions
DELETE Delete one or many objects DELETE /transactions

Selecting Objects

Select individual or multiple objects using the HTTP method GET.

Select an Individual Object

curl "https://api.payload.co/transactions/3bW9JN4CCJFkc9ukQ0umW" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE:
transaction = pl.Transaction.get('3bW9JN4CCJFkc9ukQ0umW')
transaction = Payload::Transaction.get('3bW9JN4CCJFkc9ukQ0umW')
<?php
$transaction = Payload\Transaction::get('3bW9JN4CCJFkc9ukQ0umW');
?>
pl.Transaction.get('3bW9JN4CCJFkc9ukQ0umW')
    .then(function(transaction){})
var transaction = pl.Transaction.get("3bW9JN4CCJFkc9ukQ0umW");

Select a List of Objects

curl "https://api.payload.co/transactions/?type=payment&status=processed" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE:
payments = pl.Payment.filter_by( status='processed' ).all()
payments = Payload::Payment.select( status: "processed" )
<?php
$payments = Payload\Payment::select(array('status'=>'processed'));
?>
pl.Payment.filter_by({ status: 'processed' })
    .then(function(payments){})
var payments = pl.Payment.filter_by(new { status="processed" }).all();

Request

GET https://api.payload.co/transactions/{id}

Request Multiple Objects

GET https://api.payload.co/transactions/?attr=value

Filter results using conditional queries.


Creating Objects

Create individual or multiple objects using the HTTP method POST.

Create an Individual Object

curl "https://api.payload.co/accounts/" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -d email="matt.perez@example.com" \
    -d full_name="Matt Perez" \
    -d type="customer"
account = pl.Customer.create(
    email='matt.perez@example.com',
    full_name='Matt Perez'
)
account = Payload::Customer.create(
    email: 'matt.perez@example.com',
    full_name: 'Matt Perez'
)
<?php
$account = Payload\Customer::create(array(
    'email'=>'matt.perez@example.com',
    'full_name'=>'Matt Perez'
));
?>
pl.Customer.create({
    email: 'matt.perez@example.com',
    full_name: 'Matt Perez'
}).then(function(customer) {});
var customer = pl.Customer.create(new {
    email="matt.perez@example.com",
    full_name="Matt Perez"
});

Create Multiple Objects

curl "https://api.payload.co/accounts/" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -d [0]email="matt.perez@example.com" \
    -d [0]full_name="Matt Perez" \
    -d [0]type="customer" \
    -d [1]email="andrea.kearney@example.com" \
    -d [1]full_name="Andrea Kearney" \
    -d [1]type="customer"
accounts = pl.create([
    pl.Customer(
        email='matt.perez@example.com',
        full_name='Matt Perez'
    ),
    pl.Customer(
        email='andrea.kearney@example.com',
        full_name='Andrea Kearney'
    )
])
accounts = Payload::create([
    Payload::Customer.new(
        email: 'matt.perez@example.com',
        full_name: 'Matt Perez'
    ),
    Payload::Customer.new(
        email: 'andrea.kearney@example.com',
        full_name: 'Andrea Kearney'
    )
])
<?php
$account = Payload\create(array(
    new Payload\Customer(array(
        'email'=>'matt.perez@example.com',
        'full_name'=>'Matt Perez'
    )),
    new Payload\Customer(array(
        'email'=>'andrea.kearney@example.com',
        'full_name'=>'Andrea Kearney'
    ))
));
?>
pl.create([
    new pl.Customer({
        email: 'matt.perez@example.com',
        full_name: 'Matt Perez'
    }),
    new pl.Customer({
        email: 'andrea.kearney@example.com',
        full_name: 'Andrea Kearney'
    })
]).then(function(customers) {});
var customers = pl.create(new[]{
    new pl.Account(new{
        email="matt.perez@example.com",
        full_name="Matt Perez"
    }),
    new pl.Account(new{
        email="andrea.kearney@example.com",
        full_name="Andrea Kearney"
    })
});

Create Request

POST https://api.payload.co/accounts

Request Body

{
    "email": "matt.perez@example.com",
    "full_name": "Matt Perez"
}

Create Multiple Objects

POST https://api.payload.co/accounts

Request Body

{
    "object": "list",
    "values": [
        {
            "email": "matt.perez@example.com",
            "full_name": "Matt Perez"
        },
        {
            "email": "matt.perez@example.com",
            "full_name": "Matt Perez"
        }
    ]
}


Updating Objects

Update individual or multiple objects using the HTTP method PUT.

Update an Individual Object

curl "https://api.payload.co/accounts/3bW9JMoHcb0u4ZmM7FZ32" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -X PUT \
    -d email="matt.perez@newwork.com"
account.update( email="matt.perez@newwork.com" )
account.update( email: 'matt.perez@example.com' )
<?php
$account->update(array( 'email'=>'matt.perez@example.com' ));
?>
account.update({ email: "matt.perez@newwork.com" })
account.update(new { email="matt.perez@newwork.com" });

Update Objects by Query

curl "https://api.payload.co/accounts/?email=matt.perez@example.com&type=customer&mode=query" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -X PUT \
    -d email="matt.perez@newwork.com"
accounts = pl.Customer\
    .filter_by(email='matt.perez@example.com')\
    .update(email='matt.perez@newwork.com')
accounts = Payload::Customer.select(
    email: 'matt.perez@example.com',
    update_all: {
        'email' => 'matt.perez@newwork.com'
    }
)
<?php
$accounts = Payload\Customer::select(array(
    'email'=>'matt.perez@example.com',
    'update_all'=>array(
        'email'=>'matt.perez@newwork.com'
    )
));
?>
pl.Customer
    .filter_by({ email: 'matt.perez@example.com' })
    .update({ email: 'matt.perez@newwork.com' })
    .then(function(customers){})
var customers = pl.Customer.filter_by(new {
    email="matt.perez@example.com"
}).update(new {
    email="matt.perez@newwork.com"
});

Update Multiple Objects

curl "https://api.payload.co/accounts/" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -X PUT \
    -d [0][id]="3bW9JMoHcb0u4ZmM7FZ32" \
    -d [0][email]="matt.perez@newwork.com" \
    -d [1][id]="3bW9JMojd17Dm4LSuOxIu" \
    -d [1][email]="andrea.kearney@newwork.com"
accounts = pl.update([
    [ account1, { 'email': 'matt.perez@newwork.com' } ],
    [ account2, { 'email': 'andrea.kearney@newwork.com' } ]
])
accounts = Payload::update([
    [ account1, { 'email': 'matt.perez@newwork.com' } ],
    [ account2, { 'email': 'andrea.kearney@newwork.com' } ]
])
<?php
$accounts = Payload\update(array(
    array( account1, array( 'email'=>'matt.perez@newwork.com' )),
    array( account2, array( 'email'=>'andrea.kearney@newwork.com' ))
));
?>
pl.update([
    [ account1, { email: 'matt.perez@newwork.com' } ],
    [ account2, { email: 'andrea.kearney@newwork.com' } ]
])
var customers = pl.update(new object[]{
    new object[]{ account1, new { email="matt.perez@newwork.com" } },
    new object[]{ account2, new { email="andrea.kearney@newwork.com" } }
});

Update Request

PUT https://api.payload.co/accounts/{id}

Request Body

{
    "email": "matt.perez@newwork.com"
}

Update Query

PUT https://api.payload.co/accounts/?email=matt.perez@example.com

Request Body

{
    "email": "matt.perez@newwork.com"
}

Update Multiple Objects

PUT https://api.payload.co/accounts

Request Body

{
    "object": "list",
    "values": [
        {
            "id": "3bW9JN4OEmUpEezSq6TJY",
            "email": "matt.perez@newwork.com"
        },
        {
            "id": "3bW9JN4OmbDd2Kg8bdK4W",
            "email": "andrea.kearney@newwork.com"
        }
    ]
}


Deleting Objects

Create individual or multiple objects using the HTTP method DELETE.

Delete an Individual Object

curl "https://api.payload.co/accounts/3bW9JMojd17Dm4LSuOxIu" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -X DELETE
account.delete()
account.delete()
<?php
$account->delete();
?>
account.delete()
account.delete();

Delete Objects by Query

curl "https://api.payload.co/accounts/?email=matt.perez@example.com&mode=query" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -X DELETE
deleted_accnts = pl.Customer\
    .filter_by(email='matt.perez@example.com')\
    .delete()
deleted_accnts = Payload::Customer.select(
    email: 'matt.perez@example.com',
    delete_all: true
)
<?php
$deleted_accnts = Payload\Customer::select(array(
    'email'=>'matt.perez@example.com',
    'delete_all'=>true
));
?>
pl.Customer
    .filter_by({email: 'matt.perez@example.com'})
    .delete()
    .then(function(deleted_accnts){})
var deleted_accnts = pl.Customer
    .filter_by(new { email="matt.perez@example.com" })
    .delete();

Delete Multiple Objects

curl "https://api.payload.co/accounts/" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -X DELETE \
    -d [0][id]="3bW9JN4OEmUpEezSq6TJY" \
    -d [1][id]="3bW9JN4OmbDd2Kg8bdK4W"
deleted_accnts = pl.delete([
    account1,
    account2
])
deleted_accnts = Payload::delete_all([
    account1,
    account2
])
<?php
$deleted_accnts = Payload\delete_all(array(
    account1,
    account2
));
?>
pl.delete_all([
    account1,
    account2
])
pl.delete(new[]{
    account1,
    account2
});

Delete Request

DELETE https://api.payload.co/accounts/{id}

Delete Query

DELETE https://api.payload.co/accounts/?email=matt.perez@example.com

Delete Multiple Objects

DELETE https://api.payload.co/accounts

Request Body

{
    "object": "list",
    "values": [
        {
            "id": "3bW9JN4OEmUpEezSq6TJY"
        },
        {
            "id": "3bW9JN4OmbDd2Kg8bdK4W"
        }
    ]
}


Errors

Individual Object

{
    "object": "error",
    "error_type": "InvalidAttributes",
    "details": {
        "secret_key": "Must be valid number"
    }
}

Multiple Objects

{
    "object": "error",
    "error_type": "InvalidAttributes",
    "details": {
        "object": "list",
        "values": [
            {
                "amount": "Must be a valid number"
            },
            {
                "payment_method_id": "Required"
            }
        ]
    }
}

try {
    var cust = pl.Customer.get("your_customer_id");
    cust.charge(new{ amount=100 });
} catch ( pl.NotFound e ) {
    Console.WriteLine("Customer doesn't exist");
} catch ( pl.InvalidAttributes e ) {
    // See full error
    Console.WriteLine(e.json());

    // Loop over invalid attributes
    foreach (JProperty property in e.details) {
        Console.WriteLine(property.Name+": "+property.Value);
    }
}

Errors are raised under the related HTTP 4xx Client Error or 5xx Server Error HTTP status codes. The body of the response includes more information.

Standard Error Codes

Object Operation Validation Issue

Code Name Meaning
400 Bad Request A bad request is most commonly a validation issue due to missing or malformed attributes. More information on the issue can be found in the body of the response.

Issues With Access & Permissions

Code Name Meaning
401 Unauthorized An unauthorized response is caused by an invalid or expired API secret key.
403 Forbidden A forbidden response is caused when a request is made to a resource that is not in scope of the API secret key that was used.

Requesting Nonexistent Resources

Code Name Meaning
404 Not Found A not found response is used when requesting a URL path that does not exist. If the URL path is the full object resource path, the object has likely been deleted.

API Rate Limit Reached

Code Name Meaning
429 Too Many Requests A too many requests response is raised when the API secret key, IP, or other limiting factor has reached the preset usage limit.

Internal Issues & Downtime

Code Name Meaning
500 Internal Server Error An internal server error is raised if there was an unexpected issue while processing your request.
503 Service Unavailable A service unavailable error is raised if the Payload service you’re requesting has been temporarily brought offline for maintenance.

Hierarchical Object Design

curl "https://api.payload.co/invoices/3bW9JNCxdMPBUV510Gf9E" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE:
invoice = pl.Invoice.get('3bW9JNCxdMPBUV510Gf9E')
print(invoice.json())
invoice = Payload::Invoice.get('3bW9JNCxdMPBUV510Gf9E')
puts invoice.json()
<?php
$invoice = Payload\Invoice::get('3bW9JNCxdMPBUV510Gf9E');
puts $invoice->json();
?>
pl.Invoice.get('3bW9JNCxdMPBUV510Gf9E')
    .then(function( invoice ){
        console.log(invoice.json())
    })
var invoice = pl.Invoice.get("3bW9JNCxdMPBUV510Gf9E");
Console.WriteLine( invoice.json() );
{
  "id": "3bW9JNCxdMPBUV510Gf9E",
  "object": "invoice",
  "amount": 1000,
  "description": "INV - 401",
  "due_date": "2019-02-01",
  "type": "membership",
  "items": [{
    "id": "3bW9JND5cyoQVPVcCwOkC",
    "object": "line_item",
    "amount": 100,
    "date_incurred": "2019-01-10 20:41:40",
    "description": "Item 1",
    "invoice_id": "3bW9JNCxdMPBUV510Gf9E",
    "type": "item",
    "entry_type": "charge"
  },{
    "id": "3bW9JND5l6QlItvoXYUXA",
    "object": "line_item",
    "amount": -100,
    "description": "Payment",
    "invoice_id": "3bW9JNCxdMPBUV510Gf9E",
    "entry_type": "payment",
    "payment": {
      "id": "3bW9JMonPXbEWWcNYrIm0",
      "object": "transaction",
      "account_id": "3bW9JMoMCmrCjZByd1Wt6",
      "amount": 100,
      "processing_id": "3bW9JMoN07ApUDouuPdB2",
      "description": "INV - 401 Payment",
      "fee": 1.95,
      "created_at": "2019-02-20 17:21:15",
      "payment_method": {},
      "payment_method_id": "3bW9JMoQUQiZaEV8TgPUO",
      "status": "processed",
      "type": "payment"
    }
  }]
}

Objects are often associated to other objects in the Payload API. When requesting an object like an invoice, any related objects, like line items, wil be included as nested objects within the parent invoice object’s response. This works recursively to create a hierarchical representation of an object’s relationships.

Access Nested Objects Directly

Nested objects can be accessed and manipulated directly either through an embedded object resource path, or, if the object id is known, you can access and modify it directly through the object’s full resource path.

Embedded Object Resource Path

https://api.payload.co/invoices/3bW9JNCxdMPBUV510Gf9E/items

Full Object Resource Path

https://api.payload.co/line_items/3bW9JND5cyoQVPVcCwOkC

Changes to a Nested Object Tree

You can make changes to nested objects by editing the nested object tree in an update operation.

Creating a New Nested Object

New objects added into a nested object tree without an id attribute will get created on either a create or update request.

Updating an Existing Nested Object

To update attributes of a nested object, pass the updated fields along with the object’s id in the correct nested position within the parent object in an update operation.

Deleting an Existing Nested Object

Remove the nested object from the parent’s object tree in an update operation and the object will be deleted.


API Relational Model

# An ARM api request representation
# requesting monthly aging receivables
results = pl.Invoice.select(
        attr.due_date.month(),
        attr.due_date.year(),
        attr.amount_due.sum()
    ).filter_by(
        attr.status == 'overdue',
        attr.due_date <= datetime.now() - timedelta(days=30)
    ).group_by(
        attr.due_date.month(),
        attr.due_date.year()
    ).all()
// An ARM api request representation
// requesting monthly aging receivables
results = pl.Invoice.select(
        pl.attr.due_date.month(),
        pl.attr.due_date.year(),
        pl.attr.amount_due.sum()
    ).filter_by(
        pl.attr.status.eq('overdue'),
        pl.attr.due_date.ge(new Date(new Date()-30*3600))
    ).group_by(
        pl.attr.due_date.month(),
        pl.attr.due_date.year()
    ).then(function(results){})
// An ARM api request representation
// requesting monthly aging receivables
var results = pl.Invoice.select(
        pl.attr.due_date.month(),
        pl.attr.due_date.year(),
        pl.attr.amount_due.sum()
    ).filter_by(
        pl.attr.status.eq("overdue"),
        pl.attr.due_date.le(DateTime.Now.AddDays(30))
    ).group_by(
        pl.attr.due_date.month(),
        pl.attr.due_date.year()
    ).all();

API Relational Model, or ARM, is a software library abstraction of the underlying API resources in much the same way ORMs abstract database requests. ARM combines functionality like the query language, attribute functions, and object attribute selection. The ARM representations are then compiled into API requests and executed.

The attr object

The attr object is a dot notation interface for any object attributes. Attribute functions can be called as methods of the attributes.

Using select to select attributes

The select class method can be used to specify what attributes you want in your API response. Below are the common ways to use select:

Get Additional Attributes

select can be used to request additional attributes that are not included by default for the object (more details on these additional attributes can be found in the Object Reference). To request all default attributes for an object, use *pl.Transaction wildcard operator.

Select Specific Attributes

Return a specific set of attributes by passing the desired attributes as parameters to select.

Calling Functions

Use a function to modify the value of an attribute passed to select by calling the method on the attr representation being passed to select.

Querying with filter_by

To filter the results of an API request, you can construct conditional statements with attr attributes and pass those to filter_by. filter_by uses lazy-loading and does not execute API requests immediately letting you chain filter_by calls or other non-terminal methods.

Executing the Request

Requests aren’t immediately executed when using select, filter_by, and group_by. Requests wait for an execution trigger method or are iterated. The ways in which a request execution is triggered are by using method all, first, update, or delete. Request execution is also triggered by iterating over the request or slicing the request results.


Conditional Queries

Queries can be made using query string parameters on any object or nested object attribute. You can specify advanced conditional operators like greater-than or boolean on any parameter as described below.

Select, Update, and Delete operations can be performed on query results.

Less-Than Conditional

curl "https://api.payload.co/transactions/?type=payment&amount=<200" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE:
payments = pl.Payment.filter_by(
    pl.attr.amount < 200
).all()
transactions = Payload::Payment.select(
    amount: '<200'
)
<?php
$transactions = Payload\Payment::select(array(
    'amount' => '<200'
));
?>
pl.Payment.filter_by(
        pl.attr.amount.lt(200)
    ).then(function( transactions ){
    })
var payments = pl.Payment.select(
    pl.attr.amount.lt(200)
);

Combining Less-Than and Greater-Than

curl "https://api.payload.co/transactions/?type=payment&amount=>100&amount=<200" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE:
payments = pl.Payment.filter_by(
    pl.attr.amount > 100,
    pl.attr.amount < 200
).all()
payments = Payload::Payment.select(
    amount: [ '>100', '<200' ]
)
<?php
$payments = Payload\Payment::select(array(
    'amount' => array( '>100', '<200' )
));
?>
pl.Payment.filter_by(
        pl.attr.amount.gt(100),
        pl.attr.amount.lt(200)
    ).then(function( transactions ){
    })
var payments = pl.Payment.select(
    pl.attr.amount.gt(100),
    pl.attr.amount.lt(200)
);

OR Conditional

curl "https://api.payload.co/transactions/?type=payment&risk_status=denied|in_review" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE:
payments = pl.Payment.filter_by(
    (pl.attr.risk_status == 'denied') | (pl.attr.risk_status == 'in_review')
).all()
payments = Payload::Payment.select(
    risk_status: 'denied|in_review'
)
<?php
$payments = Payload\Payment::select(array(
    'risk_status' => 'denied|in_review'
))
?>
pl.Payment.filter_by(
        pl.attr.risk_status.eq('denied','in_review')
    ).then(function( payments ){
    })
var payments = pl.Payment.filter_by(
    pl.attr.risk_status.eq("denied","in_review")
).all();

Like Conditional

payments = pl.Payment.filter_by(
    pl.attr.description.contains('INV -')
).all()
pl.Payment.filter_by(
    pl.attr.description.contains('INV -')
).then(function(payments) {
})
var payments = pl.Payment.filter_by(
    pl.attr.description.contains("INV -")
).all();

Combined Conditional Example

payments = pl.Payments.filter_by(
    pl.attr.amount > 100,
    pl.attr.amount < 200,
    (pl.attr.risk_status == 'denied') | (self.status == 'in_review'),
    pl.attr.description.contains('INV -'),
    pl.attr.created_at.date() != datetime.date(2019,2,1)
).all()
payments = pl.Payments.filter_by(
    pl.attr.amount.gt(100),
    pl.attr.amount.lt(200),
    pl.attr.risk_status.eq('denied', 'in_review'),
    pl.attr.description.contains('INV -'),
    pl.attr.created_at.date().ne(new Date(2019,1,1))
).all()
var payments = pl.Payments.filter_by(
    pl.attr.amount.gt(100),
    pl.attr.amount.lt(200),
    pl.attr.risk_status.eq("denied", "in_review"),
    pl.attr.description.contains("INV -"),
    pl.attr.created_at.date().ne(new DateTime(2019,2,1))
).all();

Nested Object Parameters

Nested objects or lists can be referenced as a query string parameter using the follow syntax:

Nested Object Parameters

?object[attr]=value

2nd Degree Nested Object Parameters

?object[subobject][attr]=value

Nested List

?list[0]=value

Nested List of Objects

?list[0][attr]=value

Query Operators

Conditional Description
attr=value Equal
attr=!value Not Equal
attr=<value Less-Than
attr=<=value Less-Than or Equal
attr=>value Greater-Than
attr=>=value Greater-Than or Equal
attr=<value1|>value2 Or
attr=!value&attr=>value And
attr=?*value* Like

Paging & Ordering Results

Example of Paging & Ordering Results

curl "https://api.payload.co/accounts/?type=customer&limit=5&offset=15&order_by=created_at" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE:
customers = pl.Customer.order_by( pl.attr.created_at )[5:15]
customers = Payload::Customer.select(
    order_by: 'created_at',
    limit: 10,
    offset: 5
)
<?php
$customers = Payload\Customer::select(array(
    'order_by' => 'created_at',
    'limit' => 10,
    'offset' => 5
));
?>
pl.Customer.select().range(1,15)
    .then(function(customers){})
var customers = pl.Customer
    .order_by( pl.attr.created_at )
    .range( 5, 15 );

Results of a query can be paged using the limit and offset query string parameters.

Paging

Attribute Description
limit=10 Limit the number of results
offset=5 Offset the results from the start of the set

Ordering

Attribute Description
order_by=created_at Results Ordering

Attributes

Every object has a predefined set of default attributes, which you can find in the object reference. Some objects also have non-default attributes which you can explicitly request to include in a response.

You also have the ability to add any custom attributes you want to any object.

Request Specific Attributes

Filter Attributes

curl "https://api.payload.co/invoices/3axWdCgzecx9HR7PSOqP2" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -d "fields[]=due_date" \
    -d "fields[]=amount_due"
results = pl.Invoice.select(
    attr.due_date, attr.amount_due ).all()
results = pl.Invoice.select(
    pl.attr.due_date, pl.attr.amount_due
).then(function(results){})
var results = pl.Invoice.select(
    pl.attr.due_date, pl.attr.amount_due ).all();

If only certain attributes are needed, you can explicitly requested which attributes you want returned.


Included Extra Attributes

curl "https://api.payload.co/invoices/3axWdCgzecx9HR7PSOqP2" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -d "fields[]=*" \
    -d "fields[]=processing_account"
results = pl.Invoice.select(
    attr.processing_account, *pl.Invoice ).all()
results = pl.Invoice.select(
    '*', pl.attr.processing_account
).then(function(results){})
var results = pl.Invoice.select(
    "*", pl.attr.processing_account ).all();

If there’s an additional attribute you want included in the response that is not a default attributes, you can specify that attribute and all default fields using the default attributes symbol, *.


Set Global Preferences

pl.Payment.default_params = { 'fields':
    [ pl.attr.cust_conv_fee, *pl.Transaction ] }
Payload::Payment.default_params = { fields: ['*'. 'cust_conv_fee' ] }
<?php
Payload\Transaction::default_params = array( 'fields' => ['*', 'cust_conv_fee'] );
?>
pl.Payment.default_params = { 'fields': ['*', 'cust_conv_fee'] }
pl.Payment.default_params = new { attrs=["*", "cust_conv_fee"] };

The software packages allow you to set global query string parameters by object resource using the default_params class attribute. You can use this to set the fields attribute to apply your preferences globally.


Set Custom Attributes

curl "https://api.payload.co/invoices/3axWdCgzecx9HR7PSOqP2" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -X PUT \
    -d "attrs[custom]=data"
inv = pl.Invoice.get('3axWdCgzecx9HR7PSOqP2')

inv.update(attrs={'custom': 'data'})
inv = Payload::Invoice.get('3axWdCgzecx9HR7PSOqP2')

inv.update(attrs: {'custom': 'data'})
<?php
$inv = Payload\Invoice.get('3axWdCgzecx9HR7PSOqP2')

$inv.update(array("attrs"=>{"custom": "data"}))
?>
pl.Invoice
    .get('3axWdCgzecx9HR7PSOqP2')
    .then(function(inv) {
        return inv.update({
            attrs: {'custom': 'data'},
        })
    })
var inv = pl.Invoice.get("3axWdCgzecx9HR7PSOqP2");

var inv.update(new { attrs=new { custom="data" } });

You can add any key/value custom attributes to any object by updating the attrs nested object.


Functions

curl "https://api.payload.co/accounts/" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -d "type=customer" \
    -d "year(created_at)=2019" \
    -d "fields=*,lower(email)"
customers = pl.Customer.select(
        pl.attr.email.lower(),
        *pl.attr
    )\
    .filter_by( pl.attr.created_at.year() == 2019 )\
    .all()
customers = Payload::Customer.select( 'year(created_at)': '2019',
    fields: '*,lower(email)' )
<?php
$customers = Payload\Customer.select(array( "year(created_at)"=>"2019",
    "fields"=>"*,lower(email)" ))
?>
pl.Customer.select(
        '*', pl.attr.email.lower(),
    ).filter_by(
        pl.attr.created_at.year() == 2019
    ).then(function(results) {
    })
var customers = pl.Customer.select(
        "*", pl.attr.email.lower()
    )
    .filter_by( pl.attr.created_at.year().eq( 2019 ) )
    .all();

Functions can be applied to attributes in either a query string conditional statement or to modify the attribute value in the response.

There are a few special aggregate functions which can only be used to modify the response, not in a conditional statement.

String Functions

lower | upper | length

Numeric Functions

abs | ceil | floor | round

Date Functions

year | month | monthname | day | dayname| dayofweek | dayofyear | weekofyear | last_day | hour | minute | second | unix_timestamp

Aggregate Functions

curl "https://api.payload.co/invoices/" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -d "due_date=>2019-01-01" \
    -d "fields=sum(amount_due),status" \
    -d "group_by=status"
invoice_stats = pl.Invoice.select(
        pl.attr.amount_due.sum(),
        pl.attr.status
    )\
    .filter_by( pl.attr.due_date >= datetime.date(2019,1,1) )\
    .group_by( pl.attr.status )\
    .all()
invoice_stats = Payload::Invoice.select( due_date: '>2019-01-01',
    fields: 'sum(amount_due),status', group_by: 'status' )
<?php
$invoice_stats = Payload\Invoice.select(array( "due_date"=>">2019-01-01",
    "fields"=>"sum(amount_due),status", "group_by"=>"status" ))
?>
pl.Invoice.select(
        pl.attr.amount_due.sum(),
        pl.attr.status
    ).filter_by(
        pl.attr.due_date.ge(new Date(2019,1,1))
    ).group_by(
        pl.attr.status
    ).then(function(results) {
    })
var results = pl.Invoice.select(
        pl.attr.amount_due.sum(),
        pl.attr.status
    ).filter_by(
        pl.attr.due_date.ge(new DateTime(2019,1,1))
    ).group_by(
        pl.attr.status
    );
[
  {
    "status": "overdue",
    "sum(amount_due)": 2389.50
  },
  {
    "status": "paid",
    "sum(amount)": 52310.00
  }
]

Aggregate functions can be used to produce an aggregated response. You can combine aggregate functions with a group_by attribute to produce grouped results.

sum | count | count_distinct | avg | min | max | variance | stddev

group_by | ?group_by=status


Timezone

By default, dates are stored and returned in UTC. You can adjust your default timezone under settings from your dashboard.


Event Model

var socket = io.connect('/client',{
    transports: ['websocket'],
    query: {
        access_token: 'secret_key_3bW9JMZtPVDOfFNzwRdfE'
    }
})

socket.on('change', function(data) {
    console.log('[' + data.evt + '] ' + data.object + ': ' + data.id)
})

From our back-end architecture to our dashboard and API, our system is built on an event-first design.

We’ve exposed this throughout our API using a socket.io protocol so you can take advantage of real-time object changes for your object scope.

Events: insert | update | delete


Payments

Charging Payments

Simple Card Payments

payment = pl.Payment.create(
    amount=100.0,
    payment_method=pl.Card(
        card_number='4242 4242 4242 4242'
    )
)
pl.Payment.create({
    amount: 100.0,
    payment_method: new pl.Card({
        card_number: '4242 4242 4242 4242'
    })
}).then(function(payment) {
})
var payment = pl.Payment.create(new {
    amount=100.0,
    payment_method=new pl.Card(new{
        card_number="4242 4242 4242 4242"
    })
});

Processing card payments starts just simply with a card number and amount. This will attempt to process the payment for a card not on file.

Please Note: Handling card numbers can expose you to PCI compliance. To avoid any PCI exposure, you can use our Checkout and Secure Input toolkits and take advantage of our end-to-end encryption and tokenization.


Simple Bank Payments

payment = pl.Payment.create(
    amount=100.0,
    payment_method=pl.BankAccount(
        account_number='1234567890',
        routing_number='021000121',
        account_type='checking'
    )
)
pl.Payment.create({
    amount: 100.0,
    payment_method: new pl.BankAccount({
        account_number: '1234567890',
        routing_number: '021000121',
        account_type: 'checking'
    })
}).then(function(payment) {
})
var payment = pl.Payment.create(new {
    amount=100.0,
    payment_method=new pl.BankAccount(new{
        account_number="1234567890",
        routing_number="021000121",
        account_type="checking"
    })
});

Processing bank account payments require both the customer’s account and routing number. This will attempt to process the payment with the customer’s bank.

Please Note: To avoid handling banking information directly, you can use our Checkout and Secure Input toolkits and take advantage of our end-to-end encryption and tokenization.


Charging a Customer

customer = pl.Customer.get('u7NDGPfjBc4uwChD')
customer.charge( amount=100 )
pl.Customer.get('u7NDGPfjBc4uwChD')
    .then(function(customer) {
        return customer.charge( amount=100 )
    }).then(function(payment) {
    })

var customer = pl.Customer.get("u7NDGPfjBc4uwChD");
customer.charge(new { amount=100 });

Charge an existing customer with payment method information on file is simple. Provide the account and amount, and Payload will attempt to run the payment with the customer’s securely stored payment details.

If the customer has multiple payment details on file, the payment attempts can cascade until a successful payment is processed.


Test Payments

To create test transactions in your test environment using the test API key you can submit dummy card numbers as long as they fit a valid format. For some samples:

Card Type Samples
Visa 4242 4242 4242 4242
MasterCard 5103 2088 7967 2792
American Express 3672 005140 64164
Discover 6011 9102 7504 5718

Handle Declines

payment = pl.Payment.create(
    amount=100.0,
    payment_method=pl.Card(
        card_number='4111 1111 1111 9903'
    )
)

if payment.status == 'decline':
    print(f'Declined: {payment.status_code}')
pl.Payment.create({
    amount: 100.0,
    payment_method: new pl.Card({
        card_number: '4111 1111 1111 9903'
    })
}).then(function(payment) {
    if ( payment.status == 'decline' )
        console.log('Declined: '+ payment.status_code)
})
var payment = pl.Payment.create(new {
    amount=100.0,
    payment_method=new pl.Card(new{
        card_number="4111 1111 1111 9903"
    })
});

if ( payment.status.Equals('decline') )
    Console.WriteLine('Declined: '+ payment.status_code);

If a payment has been declined, the payments status will return declined and the transaction’s status_code will contain one of the decline codes described below.

To trigger one of the decline code use the test number from the below table in the test environment.

Decline Code Description Test Number
card_expired The card has expired. 4111 1111 1111 9900
duplicate_attempt This transaction appears be a duplicate attempt and has been prevented. 4111 1111 1111 9901
exceeded_limit The amount of the transaction exceeds the allowed limit for this account. 4111 1111 1111 9902
general_decline The card has been declined, contact card issuer for more information. 4111 1111 1111 9903
insufficient_bal The card does not have a sufficient balance to complete the payment. 4111 1111 1111 9904
invalid_card_code The security code is invalid, please check the number. 4111 1111 1111 9905
invalid_card_number The card number is invalid, please check the number. 4111 1111 1111 9906
invalid_zip The ZIP Code does not match the card. 4111 1111 1111 9907
suspicious_activity This transaction has been identified as suspicious. 4111 1111 1111 9908
too_many_attempts Too many payment attempts have been made, please try again later. 4111 1111 1111 9909

Voids and Refunds

Void a Payment

curl "https://api.payload.co/transactions/3bW9JN4BVk3wU0ZZQs2Ay" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -X PUT \
    -d "status=voided"
payment = pl.Transaction.get('3bW9JN4BVk3wU0ZZQs2Ay')
payment.update(status='voided')
payment = Payload::Transaction.get('3bW9JN4BVk3wU0ZZQs2Ay')
payment.update(status: 'voided')
<?php
$payment = Payload\Transaction::get('3bW9JN4BVk3wU0ZZQs2Ay');
$payment->update(array( 'status' => 'voided' ))
?>
pl.Transaction.get('3bW9JN4BVk3wU0ZZQs2Ay')
    .then(function(payment){
        return payment.update({ status: 'voided' })
    })
var payment = pl.Payment.get("3bW9JN4BVk3wU0ZZQs2Ay");
payment.update(new { status="voided" });

To cancel a recent payment before it settles, simply update it’s status to voided. If a payment has already settled, you can initiate a refund instead.


Refund a Payment

curl "https://api.payload.co/transactions/" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -d "type=refund" \
    -d "amount=1000" \
    -d "ledger[0][assoc_transaction_id]=3bW9JN4BVk3wU0ZZQs2Ay"
payment = pl.Payment.get('3bW9JN4BVk3wU0ZZQs2Ay')

refund = pl.Refund.create(
    amount=payment.amount,
    ledger=[{
        'assoc_transaction_id': payment.id
    }]
)
payment = Payload::Payment.get('3bW9JN4BVk3wU0ZZQs2Ay')

refund = Payload::Refund.create(
    amount: payment.amount,
    ledger: [{
        'assoc_transaction_id' => payment.id
    }]
)
<?php
$payment = Payload\Payment::get('3bW9JN4BVk3wU0ZZQs2Ay');

$refund = Payload\Refund::create(array(
    'amount' => $payment->amount,
    'ledger' => array(array(
        'assoc_transaction_id' => $payment->id
    ))
));
?>
pl.Payment.get('3bW9JN4BVk3wU0ZZQs2Ay')
    .then(function(payment){
        return pl.Refund.create({
            amount: payment.amount,
            ledger: [{
                assoc_transaction_id: payment.id
            }]
        })
    })
var payment = pl.Payment.get("3bW9JN4BVk3wU0ZZQs2Ay");

var refund = pl.Refund.create(new {
    amount=payment.amount,
    ledger=new[]{
        new pl.Ledger(new{ assoc_transaction_id=payment.id })
    }
});

// Or the short form
var refund = payment.refund();

To refund a payment, create a new refund transaction with a ledger entry setting the assoc_transaction_id to the original payment.


Chargebacks and Rejects

Chargebacks

curl "https://api.payload.co/transactions/?type=chargeback&created_at=>2019-01-01&fields=*,ledger" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE:
chargebacks = pl.Chargeback.select(
        pl.attr.ledger,
        *pl.Transaction
    )\
    .filter_by(
        created_at=datetime.date(2019,1,1)
    )


for chargeback in chargebacks:
    print(chargeback.ledger[0].assoc_transaction_id)
    # The id of the associated payment
chargebacks = Payload::Chargeback.select(
    created_at: '>2019-01-01',
    fields: '*,ledger'
)

for chargeback in chargebacks
    puts chargeback.ledger[0].assoc_transaction_id
    # The id of the associated payment
end
<?php
$chargebacks = Payload\Chargeback::select(array(
    'created_at' => '>2019-01-01',
    'fields' => '*,ledger'
))

foreach( $chargebacks as $chargeback ) {
    echo $chargeback->ledger[0]->assoc_transaction_id;
    # The id of the associated payment
}
?>
pl.Chargeback.select(
    '*', pl.attr.ledger
).filter_by(
    pl.attr.created_at.gt(new Date(2019,1,1))
).then(function(chargebacks){
    for ( var i = 0; i < chargebacks.length; i++ ) {
        var chargeback = chargebacks[i]
        console.log( chargeback.ledger[0].assoc_transaction_id )
        // The id of the associated payment
    }
})

var chargebacks = pl.Chargeback.select(
        "*", pl.attr.ledger,
    )
    .filter_by(new {
        created_at=new DateTime(2019,01,01)
    });


foreach ( var chargeback in chargebacks ) {
    Console.WriteLine( chargeback.ledger[0].assoc_transaction_id );
    // The id of the associated payment
}

A chargeback is the result of a customer disputing a payment. This can be caused by suspected fraud, a claim of services not rendered, or unauthorized payment. Chargebacks result in the bank reversing the original payment. If a dispute is overturned, the funds will be returned as a chargeback_reversal transaction type.

Chargebacks have type chargeback and are associated to the original payment through the ledger.

Your disputes can be managed through disputes dashboard.


Bank Account Rejects

curl "https://api.payload.co/transactions/?status=rejected&rejected_on=>2019-02-01" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE:
rejected_payments = pl.Payment.filter_by(
    pl.attr.status=='rejected',
    pl.attr.rejected_on>=datetime.date(2019,1,1)
)

for payment in rejected_payments:
    print(payment.status_code)
rejected_payments = Payload::Payment.select(
    status: 'rejected',
    rejected_on: '>2019-01-01'
)

for payment in rejected_payments
    puts payment.status_code
end
<?php
$rejected_payments = Payload\Payment::select(array(
    'status' => 'rejected',
    'rejected_on' => '>2019-01-01'
))

foreach( $rejected_payments as $payment ) {
    echo $payment->status_code;
}
?>
pl.Payment.select(
    pl.attr.status.eq('rejected'),
    pl.attr.rejected_on.gt(new Date(2019,1,1))
).then(function(rejected_payments){
    for ( var i = 0; i < rejected_payments.length; i++ ) {
        var payment = rejected_payments[i]
        console.log( payment.status_code )
    }
})
var rejected_payments = pl.Payment.filter_by(
    pl.attr.status.eq("rejected"),
    pl.attr.rejected_on.ge(new DateTime(2019,1,1))
);

foreach( var payment in rejected_payments )
    Console.WriteLine( payment.status_code );

Bank account payments don’t decline instantly like card payments and can be rejected by the bank for reasons like insufficient funds or incorrect account number a few days after they were originally processed.


Types of Transactions

Type Description
payment A customer’s payment.
deposit A settlement of processed payments sent to a processing account funding method.
refund A return of a payment (full or partial).
reversal Debit the processing account for refunds or chargebacks.
chargeback A return of the original payment from a disputed payment.
chargeback_reversal A transaction recovering the returned funds from an overturned chargeback and .
Status Description
authorized An authorization for a payment. The payment can be set to process at a later date.
processed A transaction that has processed successfully.
voided A canceled transaction before any transfer was initiated.
declined A payment attempt that was unsuccessful.
rejected A bank account payment that was rejected by the bank.

Processing Accounts

Select all active processing accounts

curl "https://api.payload.co/accounts/?processing[status]=active" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE:
processing_account = pl.ProcessingAccount.filter_by(
    processing={ 'status': 'active' }
).all()
processing_account = Payload::ProcessingAccount.filter_by(
    processing: { 'status': 'active' }
)
<?php
$processing_account = new Payload\ProcessingAccount::filter_by(array(
    'processing' => array( 'status' => 'active )
))
?>
processing_accounts = pl.ProcessingAccount.filter_by({
    processing: { 'status': 'active' }
}).all()
var processing_account = pl.ProcessingAccount.filter_by(new {
    porcessing=new { status="active" }
});

Every payment needs to be associated with an active Processing Account to process. Processing Accounts specify the pricing and settings for how payments should be processed, including what funding account to transmit the payment to.

Processing Accounts can be added through the dashboard or the full setup process can be integrated into your platform using the Integrated Processing Account Setup toolkit.

Using Processing Accounts

Using your processing account is simple. Once your account is activated, all it comes down to is selecting the right account for your transactions.

payment = pl.Payment.create(
    amount=100.0,
    processing_account_id=processing_account.id,
    payment_method=pl.Card(
        card_number='4242 4242 4242 4242'
    )
)
payment = pl.Payment.create({
    amount: 100.0,
    processing_account_id: processing_account.id,
    payment_method: new pl.Card({
        card_number: '4242 4242 4242 4242'
    })
})
var payment = pl.Payment.create(new {
    amount=100.0,
    processing_account_id=processing_account.id,
    payment_method=new pl.Card(new{
        card_number="4242 4242 4242 4242"
    })
});

Paying a Processing Account

When making a payment, pass the id of the desired processing account with the payment as the processing_id parameter.

# If no processing account is specified
# the default account will be used automatically
payment = pl.Payment.create(
    amount=100.0,
    payment_method=pl.Card(
        card_number='4242 4242 4242 4242'
    )
)
// If no processing account is specified
// the default account will be used automatically
payment = pl.Payment.create({
    amount: 100.0,
    payment_method: new pl.Card({
        card_number: '4242 4242 4242 4242'
    })
})
// If no processing account is specified
// the default account will be used automatically
var payment = pl.Payment.create(new {
    amount=100.0,
    payment_method=new pl.Card(new{
        card_number="4242 4242 4242 4242"
    })
});

Setting a Default Account

You can set a default processing account on the dashboard, or by flipping the default attribute to true.

Any payment that is submitted without a processing_id specified will automatically select the default processing account.

Segmenting Customers

If you are using Customers to manage your customer accounts, you can specify a primary processing account for each customer by setting the primary_processing_id.

Any payment made for this customer without a processing_id specified will default to the primary_processing_id.


Processing Activation

Check the activation status

curl "https://api.payload.co/accounts/3bW9JMapnT7sw7neax7ui" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE:
processing_account = pl.ProcessingAccount.get('3bW9JMapnT7sw7neax7ui')

print(processing_account.processing.status)
processing_account = Payload::ProcessingAccount.get('3bW9JMapnT7sw7neax7ui')

puts processing_account.processing.status
<?
$processing_account = Payload\ProcessingAccount::get('3bW9JMapnT7sw7neax7ui');

echo(processing_account->processing.status);
?>
payload.ProcessingAccount.get('3bW9JMapnT7sw7neax7ui')
    .then(function(processing_account){
        console.log(processing_account.processing.status)
    })
var processing_account = pl.ProcessingAccount.get('3bW9JMapnT7sw7neax7ui');

Console.Log(processing_account.processing.status);

A processing account generally takes 24 business hours for full payment processing activation. Sometimes the information submitted for the processing account is incorrect and will require you to update the information to proceed.

Below is a breakdown of the different statuses for a Processing Account.

Status Description
pending The new processing account activation is underway.
active The processing account has been activated.
in_review The processing account has been put into a review process which can take 3-5 days.
update_required Some of information submitted for the processing account needs to be updated.
inactive The processing account has set to inactive.

Changes to the status can be monitored using the processing_status webhook.


Integrated Processing Setup

To integrate the processing account setup into your app or platform, you can use the Processing Account ui toolkit to capture the details for a new processing account.

Example

Below is an example of the Processing Account form. Click the button to view.

<script src="https://payload.co/Payload.js"
  pl-client-key="client_key_AWcpDnNBB7oLfNqfQ6g66262"
  pl-btn-open="processing-account">
</script>
<script>
var pl = Payload('client_key_AWcpDnNBB7oLfNqfQ6g66262')
new pl.ProcessingAccount()
    .on('account_created', function(evt) {
        console.log(evt.account.id)
    })
</script>

Open the Processing Form

You can open the Processing Account form using the Payload inline script tag with the pl-btn-open parameter set to processing-account.

The Processing Account plugin can be opened using the javascript interface by creating a new instance of Payload.ProcessingAccount, as seen in the example.


JavaScript Events

<script>
Payload.on( '.processing-button', 'account_created', function(evt) {
    console.log('handle event')
})
</script>

The processing form has different JavaScript events that you can watch for. To watch for an event on a Payload Button, you can pass either the element or a css selector as the first parameter.

Event Description
account_created Event triggered after the form has been successfully completed.
loaded Event triggered after the form has loaded
closed Event triggered after the form has been closed

Configuration

Attribute Description
pl-client-key
required
Your client key
pl-btn-open
required
Value must be processing-account
pl-btn-class CSS class to apply to the button.
pl-btn-text Display text for the button.

JavaScript

Parameter Description
client_key
required
Your client key
form Specify a form element to auto-submit with the account id once an application is processed.

Fee & Pricing Control

Net or Gross Deposits

Net Deposits

Processing fees by default are configured to be netted out of the deposit to the processing account. The total fee amount netted from a deposit can be found in the fee attribute. If your account is configured for gross deposits, the fee attribute will be zero.

Gross Deposits

If your processing account is set to gross deposits, your processing fees will be deducted monthly. By default, the fees will be debited directly from the processing account funding method but you can override this to use a separate account.

Convenience Fees

curl "https://api.payload.co/transactions/3bW9JN4BVk3wU0ZZQs2Ay?field=*,cust_conv_fee" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE:
payment = pl.Payment.select(
        pl.attr.cust_conv_fee,
        *pl.Payment
    )\
    .get('3bW9JN4BVk3wU0ZZQs2Ay')

print(payment.fee) # Fee charged to the processing account
print(payment.cust_conv_fee) # Fee charged to the customer
payment = Payload::Payment.get('3bW9JN4BVk3wU0ZZQs2Ay',
    fields: '*,cust_conv_fee')

puts payment.fee # Fee charged to the processing account
puts payment.cust_conv_fee # Fee charged to the customer
<?php
$payment = Payload\Payment::get('3bW9JN4BVk3wU0ZZQs2Ay');

echo $payment->fee; # Fee charged to the processing account
echo "\n";
echo $payment->cust_conv_fee; # Fee charged to the customer
echo "\n";
?>
pl.Payment.select( '*', pl.attr.cust_conv_fee )
    .get('3bW9JN4BVk3wU0ZZQs2Ay')
    .then(function(payment){
        console.log(payment.fee) // Fee charged to the processing account
        console.log(payment.cust_conv_fee) // Fee charged to the customer
    })
var payment = pl.Payment
    .select( '*', pl.attr.cust_conv_fee )
    .get("3bW9JN4BVk3wU0ZZQs2Ay");

Console.WriteLine( payment.fee ); // Fee charged to the processing account
Console.WriteLine( payment.cust_conv_fee ); // Fee charged to the customer

By using Paylaod Checkout, you can configure certain fees to be charged as a convenience for different types of payment methods. You can configure how much of the processing fee you want to cover, e.g.: all, none, or part of the fee. This can be set differently by payment method, i.e.: debit card, credit card, or bank account and can also be different for different parts of your application. The convenience fee amount is stored in a different attribute, cust_conv_fee.

Adjustable Rates

Rates can be adjustable based on industry, volume, and type, i.e.: debit card, credit card, and bank account payments.

For more information, please reach out at sales@payload.co.

Platform Upcharging

For platforms offering Payload payment services to their customers, if applicable for our rev-share program, platforms can add an upcharge to their processing rates.

For more information, please reach out at sales@payload.co.


Checkout

Payload Checkout is a ui toolkit for integrating simple payment acceptance into your portal or platform. Below are a few of built-in the benefits of accepting payments using the checkout toolkit.

If your platform has recurring customers, you can create Customer accounts and store your customers payment information and settings for fast checkout and simple recurring billing.

Example

Below is a simple example of Payload Checkout. Click Pay Now to view.

Pay Now Button

<form action="/submit_payment" method="POST">
  <script src="https://payload.co/Payload.js"
    pl-client-key="client_key_AWcpDnNBB7oLfNqfQ6g66262"
    pl-amount="100.00"
    pl-description="Membership">
  </script>
</form>

Step 1) Script Tag

Use the script tag to embed a Pay Now button into your form. This will open an instance of Payload Checkout to accept a new payment.

Step 2) Form Submit

Once a payment is confirmed, a hidden input, <input type="hidden" name="pl_transaction_id" value="{id}">, is added to the form element and then Payload.js automatically submits the form.

Step 3) Server Confirmation

pl_transaction_id = '19QsDurdSxJ0gVNzOcQSlew3D'
curl "https://api.payload.co/transactions/$pl_transaction_id" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -X PUT \
    -d status=processed
import payload as pl
pl.api_key = 'secret_key_3bW9JMZtPVDOfFNzwRdfE'

@server.route('/submit_payment', method='post')
def post_transaction(pl_transaction_id):
    pl.Transaction(id=pl_transaction_id)\
        .update(status='processed')
require 'payload'
Payload.api_key = 'secret_key_3bW9JMZtPVDOfFNzwRdfE'

post '/submit_payment/' do
    pl_transaction_id = params[:pl_transaction_id]

    transaction = Payload::Transaction.get(
        pl_transaction_id,
        update: { 'status' => 'processed' }
    )
end
<?php
Payload\Payload::$api_key = 'secret_key_3bW9JMZtPVDOfFNzwRdfE';

$pl_transaction_id = $_GET['pl_transaction_id'];

$transaction = Payload\Transaction::get(
    pl_transaction_id,
    array( 'status' => 'processed' )
);
?>
var pl = require('payload-api')
pl.api_key = 'secret_key_3bW9JMZtPVDOfFNzwRdfE'

app.post('/submit_payment', (req, res) => {
    var pl_transaction_id = req.body.pl_transaction_id
    pl.Transaction({ id: pl_transaction_id })
        .update({ status: 'processed' })
        .then(function() {
            res.send('Payment Successful!')
        })
})
pl.api_key = "secret_key_3bW9JMZtPVDOfFNzwRdfE";

string pl_transaction_id = "19QsDurdSxJ0gVNzOcQSlew3D";

new pl.Payment(new{
    id=pl_transaction_id
}).update(new { status="processed" });

On the server side, you must confirm the pl_transaction_id.

The transaction has only been authorized at this point. To confirm the transaction you need to update the status from authorized to processed as seen in the example.


JavaScript Interface

Step 1) Open via JavaScript

<script src="https://payload.co/Payload.js"></script>

<script>
var pl = Payload('client_key_AWcpDnNBB7oLfNqfQ6g66262')
var checkout = new pl.Checkout({
    amount: 1000.0,
    description: "Example Payment"
})
</script>

Payload Checkout can be opened using the javascript interface by creating a new instance of Payload.Checkout, as seen in the example.

You can have Payload Checkout automatically submit a form after a successful payment by passing the form element as the form parameter when creating the checkout instance.


Step 2) Watch for Callback

<script>
checkout.on('processed', function(evt) {
    $.post('/submit_payment',
        { pl_transaction_id: evt.transaction_id })
})
</script>

When using the JavaScript interface and Checkout is not embedded within a form, you can watch for the processed callback to receive the transaction id.

Once you receive the transaction id you will need to send that to the server using an asynchronous request or trigger your own form submit.

Step 3) Server Confirmation

pl_transaction_id = '19QsDurdSxJ0gVNzOcQSlew3D'
curl "https://api.payload.co/transactions/$pl_transaction_id" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -X PUT \
    -d status=processed
import payload as pl
pl.api_key = 'secret_key_3bW9JMZtPVDOfFNzwRdfE'

@server.route('/submit_payment', method='post')
def post_transaction(pl_transaction_id):
    pl.Transaction(id=pl_transaction_id)\
        .update(status='processed')
require 'payload'
Payload.api_key = 'secret_key_3bW9JMZtPVDOfFNzwRdfE'

post '/submit_payment/' do
    pl_transaction_id = params[:pl_transaction_id]

    transaction = Payload::Payment.get(
        pl_transaction_id,
        update: { 'status' => 'processed' }
    )
end
<?php
Payload\Payload::$api_key = 'secret_key_3bW9JMZtPVDOfFNzwRdfE';

$pl_transaction_id = $_GET['pl_transaction_id'];

$transaction = Payload\Transaction::get(
    pl_transaction_id,
    array( 'status' => 'processed' )
);
?>
var pl = require('payload-api')
pl.api_key = 'secret_key_3bW9JMZtPVDOfFNzwRdfE'

app.post('/submit_payment', (req, res) => {
    var pl_transaction_id = req.body.pl_transaction_id
    pl.Payment({ id: pl_transaction_id })
        .update({ status: 'processed' })
        .then(function() {
            res.send('Payment Successful!')
        })
})
pl.api_key = "secret_key_3bW9JMZtPVDOfFNzwRdfE";

string pl_transaction_id = "19QsDurdSxJ0gVNzOcQSlew3D";

new pl.Payment(new{
    id=pl_transaction_id
}).update(new { status="processed" });

On the server side, you must confirm the pl_transaction_id using the transactions api.

The transaction has only been authorized at this point. To confirm the transaction you need to update the status from authorized to processed as seen in the example.


JavaScript Callbacks

<script>
Payload.on( '.checkout-btn', 'processed', function(evt) {
    console.log('handle event')
})
</script>

Payload Checkout has different JavaScript events that you can watch for. To watch for an event on a Payload Button, you can pass either the element or a css selector as the first parameter.

Event Description
loaded Event triggered after the form has been successfully completed
processed Event triggered after a payment has been processed successfully
declined Event triggered if a payment attempt was declined
closed Event triggered after the form has been closed

Checkout Configuration

Script Tag Attributes

Attributes Description
pl-client-key
required
Your client key.
pl-amount
required without invoice-id
The payment amount.
pl-amount-editable
optional
Allow custom amounts.
pl-description
required without invoice-id
A description of the payment.
pl-order-number If you have a specific order number, include it to reference the transaction later.
pl-processing-id The processing account id for the payment.
pl-customer-id Load an existing customer’s account settings. See the Customers section for more information.
pl-card-payments
default: true
Specifies if payments via card are accepted.
pl-bank-account-payments
default: false
Specifies if payments via bank account are accepted.
pl-billing-address Use true or false to specify whether billing address fields are displayed. Default is false.
pl-email The customer’s email address, if available.
pl-name The customer’s name, if available.
pl-invoice-id To tie the resulting payment to an invoice, pass the invoice id value.
pl-auto-billing-toggle Adds an option to allow customer to set payment method as billing default.
pl-conv-fee Use true or false to specify whether fee should be charged as a convenience.
pl-attrs Transaction custom attributes JSON object. Example: data-attrs='{"example":"data"}'
pl-btn-class CSS class to apply to the button.
pl-btn-text Display text for the button.
pl-type
default: popup-btn
Choose between popup-btn and inline.

JavaScript Attributes

Attributes Description
key
required
Your client key.
amount
required without invoice id
The payment amount.
description
required
A description of the payment.
amount_editable
optional
Allow custom amounts.
processing_id
optional
The processing account id for the payment.
customer_id
optional
The customer’s account id.
card_payments
default: true
Specifies if payments via card are accepted.
bank_account_payments
default: false
Specifies if payments via bank account are accepted.
billing_address Use true or false to specify whether billing address fields are displayed. Default is false.
email The customer’s email address, if available.
full_name The customer’s full name, if available.
invoice_id To tie the resulting payment to an invoice, pass the invoice id value.
auto_billing_toggle Adds an option to allow customer to set payment method as billing default.
attrs Transaction custom attributes JSON object. Example: {"example":"data"}
conv_fee Use true or false to specify whether fee should be charged as a convenience.
inline An html element to embed the interface instead of a popup.
form If present, following a successful payment the form will be submitted with the pl_transaction_id parameter.

Secure Input

Use Secure Input for capturing card or bank account details securely from within any html form.

How Does it Work?

<!-- Secure Input required Payload.js -->
<script src="https://payload.co/Payload.js"></script>

Payload’s Secure Input library will capture the sensitive card or bank account details from the customer, pass the details directly to Payload’s secure PCI environment, and return either a transaction id or a payment method id.

Secure Inputs offer a lot of flexibility for customizing the user experience of capturing payment details without introducing security concerns to your app by handling sensitive card and bank account details.

Creating a Form

Bootstrap 4 Example

<form id="checkout-form" class="container" pl-form="payment">
    <input type="hidden" pl-input="amount" value="10.00">
    <div class="row pt-2">
        <div class="form-group col-7 px-1">
            <label>Card Number</label>
            <div class="form-control" pl-input="card_number"></div>
        </div>
        <div class="form-group col-3 px-1">
            <label>Expiration</label>
            <div class="form-control" pl-input="expiry"></div>
        </div>
        <div class="form-group col-2 px-1">
            <label>CVC</label>
            <div class="form-control" pl-input="cvc"></div>
        </div>
    </div>
    <div class="row pt-2">
        <button class="btn btn-primary" type="submit">Pay Now</button>
    </div>
</form>
<script>
var pl = Payload('UPDATE WITH YOUR test_client_key_....')

var checkout_form = new pl.Form({
    form: $('#checkout-form').get(0)
})
</script>

Creating a form with Payload Secure Inputs requires just a few html attributes and a JavaScript call to initialize. Follow the below steps to setup a form:

1) Tag the Form

Create an html <form> element and tag the form with the pl-form attribute.

<form pl-form="payment"></form>


The pl-form attribute accepts a value of either payment or payment_method.

Payment Form

The payment form type should be used if the form is intended to process a payment, or checkout, immediately once the form is completed.

Payment Method Form

The payment_method form type should be used if the form is intended to capture payment and billing details to be stored for future payments.

2) Create the Inputs

There are two types of inputs you can add to your form. Secured inputs for the card number and other sensitive data fields that need to be <div> element or data inputs for things like the payment amount or other data fields that don’t contain sensitive data and can be a standard html <input>.

Both input types require the pl-input html attribute.

Secured Inputs

Secured inputs need to be a <div> element type with the pl-input attribute.

<div pl-input="card_number"></div>


Secure input types include:


Data Inputs

Data inputs are standard <input> elements with the pl-input attribute for any data field that should be included in the request to Payload.

<input type="hidden" pl-input="amount" value="10.00">


Data inputs can be any attribute in the object tree, some common fields include:

3) Initialize with JavaScript

After the form and the inputs have been created, initialize the form by passing the form element to a new pl.Form object using Payload’s JavaScript interface.

<script>
var pl = Payload('test_client_key_....')
new pl.Form(document.getElementById('checkout-form'))
</script>


Handling Results

Once a form submit is triggered, a request is sent to Payload with only the data from the secure inputs within the form. If the request to payload is successful, the form submit proceeds as normal. If the request is unsuccessful, the invalid inputs are shown as invalid.

Successful Result

If the request to Payload was successful, a hidden element containing the new object’s id will be embedded into the form. If the pl-form attribute was set to payment then an input with the name pl_transaction_id will be added to the form. If the pl-form attribute was set to payment_method then an input with the name pl_payment_method_id will be added to the form.

<input type="hidden" name="pl_transaction_id" value="<id of new payment>">


Once this input has been added to the form, a form submit is triggered.

Override Form Submit

<script>
var checkout = new pl.Form({
    form: document.getElementById('checkout-form'),
    autosubmit: false
}).on('processed',function(evt) {
    /*handle response*/
})
</script>

If you want to handle the form in a different way and don’t want it to submit, you can use the autosubmit: false option when initializing the form. You can watch for the JavaScript events and handle the results in another manner.


Invalid

<script>
var checkout = new pl.Form(document.getElementById('checkout-form'))
    .on('invalid',function(evt) {
        /*handle invalid data*/
    })
    .on('error',function(evt) {
        /*handle bad request*/
    })
</script>

If the request to Payload is invalid, the pl-invalid css class will be applied to any invalid inputs. Note: the default invalid css classname can be changed

There is also an invalid and an error event that can be used for custom error handling. The invalid event will only fire if any of the input fields contained invalid values. The error event will trigger for any error response from the API request. Please see the errors section for more information on possible error responses.


Styling Inputs

You can style any input by adding your own classes or css rules, or by extending the payload classes. It’s also possible to override the default classnames using the JavaScript styles option.

Using the Bootstrap 4 invalid class

<script>
new pl.Form({
    form: document.getElementById('checkout-form'),
    styles: { invalid: 'is-invalid' }
})
</script>

Payload default classes:

An example of styling for Bootstrap 4

Input Options

Payment

Name Description
amount The amount of the payment

Cards

Name Description
card_number secure Card number
expiry secure Expiration of the card
cvc secure Code on the back of the card
account_holder Name of the cardholder

Bank Accounts

Name Description
account_number secure The bank account number
routing_number secure The ACH routing number for the account
account_type Either checking or savings
account_class optional Either personal or business
account_holder Signer for the account

Billing Details

Name Description
billing_address[street_address] optional
billing_address[unit_number] optional
billing_address[city] optional
billing_address[state_province] optional
billing_address[postal_code] optional

JavaScript Interface

Form Options

Name Description
form The html form element
autosubmit optional Specify if the form submit should trigger. Default: true
styles optional Change the default classnames

Events

Name Description
processing Triggered once a request is sent to Payload
processed Triggered if the payment was successfully processed
declined Triggered if the payment was declined
created Triggered if the payment method was successfully saved
invalid Triggered if the any of the input field values were invalid
error Triggered for any API error response

React Component Library

Use the payload-react component library when integrating Secure Input with React.

Installation

npm install payload-react

View on Github

Examples


Payment Links

Payload Payment Links are a simple and useful tool for accepting payments via secure links. A payment link will generate a stand-alone payment page that can be sent via email or linked to from any webpage as either a one-time or reusable link.

Basic One-time Link

curl "https://api.payload.co/payment_links/" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -d type="one_time" \
    -d description="Payment Request" \
    -d amount="10" \
    -d processing_id="3brhxEXpz2qEJ8vnIXbvW"
payment_link = pl.PaymentLink.create(
    type='one_time',
    description='Payment Request',
    amount=10.00, # Optional
    processing_id='3brhxEXpz2qEJ8vnIXbvW'
)
payment_link = Payload::PaymentLink.create(
    type: 'one_time',
    description: 'Payment Request',
    amount: 10.00, # Optional
    processing_id: '3brhxEXpz2qEJ8vnIXbvW'
)
<?php
$payment_link = Payload\PaymentLink::create(array(
    'type' => 'one_time',
    'description' => 'Payment Request',
    'amount' => 10.00, # Optional
    'processing_id' => '3brhxEXpz2qEJ8vnIXbvW'
));
?>
pl.PaymentLink.create({
    type: 'one_time',
    description: 'Payment Request',
    amount: 10.00,  /* Optional */
    processing_id: '3brhxEXpz2qEJ8vnIXbvW'
}).then(function(payment_link){})
var payment_link = pl.PaymentLink.create(new {
    type="one_time",
    description="Payment Request",
    amount=10.00, /* Optional */
    processing_id="3brhxEXpz2qEJ8vnIXbvW"
});

Creating a basic link just requires a short description and the processing_id of the payment. You can either specify an amount or allow the client to enter the amount themselves. Payment links also accept a customer_id which will enable an automatic email to be sent directly to the client.


Include Additional Data Fields

Additional Data Fields

curl "https://api.payload.co/payment_links/" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -d type="one_time" \
    -d description="Payment Request" \
    -d amount="10" \
    -d processing_id="3brhxEXpz2qEJ8vnIXbvW"
    -d additional_datafields='[{"section":"Extra Fields","fields":[{"title:"Field Name"}]}]'
payment_link = pl.PaymentLink.create(
    type='one_time',
    description='Payment Request',
    amount=10.00,
    processing_id='3brhxEXpz2qEJ8vnIXbvW',
    additional_datafields=[{
        'section': 'Extra Fields',
        'fields': [{ 'title': 'Field Name' }]
    }]
)
payment_link = Payload::PaymentLink.create(
    type: 'one_time',
    description: 'Payment Request',
    amount: 10.00,
    processing_id: '3brhxEXpz2qEJ8vnIXbvW',
    additional_datafields: [{
        section: 'Extra Fields',
        fields: [{ title: 'Field Name' }]
    }]
)
<?php
$payment_link = Payload\PaymentLink::create(array(
    'type' => 'one_time',
    'description' => 'Payment Request',
    'amount' => 10.00,
    'processing_id' => '3brhxEXpz2qEJ8vnIXbvW',
    'additional_datafields' => array(array(
        'section' => 'Extra Fields',
        'fields' => array(array( 'title' => 'Field Name' ))
    ))
));
?>
pl.PaymentLink.create({
    type: 'one_time',
    description: 'Payment Request',
    amount: 10.00,
    processing_id: '3brhxEXpz2qEJ8vnIXbvW',
    additional_datafields: [{
        section: 'Extra Fields',
        fields: [{ title: 'Field Name' }]
    }]
}).then(function(payment_link){})
var payment_link = pl.PaymentLink.create(new {
    type="one_time",
    description="Payment Request",
    amount=10.00,
    processing_id="3brhxEXpz2qEJ8vnIXbvW",
    additional_datafields: new []{new{
        section='Extra Fields',
        fields=new []{new{ title='Field Name' }}
    }}
});

If there are additional data or form fields that should be collected with each payment, additional_datafields can accept a list of additional fields grouped by sections. The resulting data field values will be stored in the resulting payment attrs object.


Reusable-time Link

curl "https://api.payload.co/payment_links/" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -d type="reusable" \
    -d description="Payment Request" \
    -d processing_id="3brhxEXpz2qEJ8vnIXbvW"
payment_link = pl.PaymentLink.create(
    type='reusable',
    description='Payment Request',
    processing_id='3brhxEXpz2qEJ8vnIXbvW'
)
payment_link = Payload::PaymentLink.create(
    type: 'reusable',
    description: 'Payment Request',
    processing_id: '3brhxEXpz2qEJ8vnIXbvW'
)
<?php
$payment_link = Payload\PaymentLink::create(array(
    'type' => 'reusable',
    'description' => 'Payment Request',
    'processing_id' => '3brhxEXpz2qEJ8vnIXbvW'
));
?>
pl.PaymentLink.create({
    type: 'reusable',
    description: 'Payment Request',
    processing_id: '3brhxEXpz2qEJ8vnIXbvW'
}).then(function(payment_link){})
var payment_link = pl.PaymentLink.create(new {
    type="reusable",
    description="Payment Request",
    processing_id="3brhxEXpz2qEJ8vnIXbvW"
});

A reusable secure payment link can be used as a static page to accept as many payments as needed. Reusable links are great for adding a static link directly from any website or page that may be used to collect a payment from visitors.


Customer Link

curl "https://api.payload.co/payment_links/" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -d type="one_time" \
    -d description="Payment Request" \
    -d customer[name]="Test Customer" \
    -d customer[email]="testcustomer@gmail.com" \
    -d processing_id="3brhxEXpz2qEJ8vnIXbvW"
payment_link = pl.PaymentLink.create(
    type='one_time',
    description='Payment Request',
    processing_id='3brhxEXpz2qEJ8vnIXbvW',
    customer=pl.Customer(
        name='Test Customer',
        email='testcustomer@gmail.com'
    )
)
payment_link = Payload::PaymentLink.create(
    type: 'one_time',
    description: 'Payment Request',
    processing_id: '3brhxEXpz2qEJ8vnIXbvW',
    customer: Payload::Customer(
        name: 'Test Customer',
        email: 'testcustomer@gmail.com'
    )
)
<?php
$payment_link = Payload\PaymentLink::create(array(
    'type' => 'one_time',
    'description' => 'Payment Request',
    'processing_id' => '3brhxEXpz2qEJ8vnIXbvW',
    'customer'=Payload\Customer(array(
        'name' => 'Test Customer',
        'email' => 'testcustomer@gmail.com'
    ))
));
?>
pl.PaymentLink.create({
    type: 'one_time',
    description: 'Payment Request',
    processing_id: '3brhxEXpz2qEJ8vnIXbvW',
    customer: pl.Customer(
        name: 'Test Customer',
        email: 'testcustomer@gmail.com'
    )
}).then(function(payment_link){})
var payment_link = pl.PaymentLink.create(new {
    type="one_time",
    description="Payment Request",
    processing_id="3brhxEXpz2qEJ8vnIXbvW",
    customer=pl.Customer(new{
        name="Test Customer",
        email="testcustomer@gmail.com"
    })
});

An email can be automatically triggered by providing a customer’s name and email address or an existing customer_id when instantiating a secure payment link. The customer will receive an email with details on the requested payment and a secure link to the payment page where they’ll be able to complete the payment.


Reusable-time Link

print(payment_link.url)
puts(payment_link.url)
<?php
echo($payment_link=>url);
?>
console.log(payment_link.url)
Console.WriteLine(payment_link.url);

Every payment link object includes a url that can be sent to a client for payment or can be added to any website or page.


Handling Successful Payment

The customer and admin will receive email receipts after a successful payment. A redirect url can be provided as well which will redirect the page after a payment has been completed.


Customers

Customer accounts provide a simple way to organize and simplify your recurring customer’s purchases and payment settings.

With customer accounts you can:

Creating Customers

Create a New Customer

curl "https://api.payload.co/accounts/" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -d email="matt.perez@example.com" \
    -d full_name="Matt Perez" \
    -d type="customer"
account = pl.Customer.create(
    email='matt.perez@example.com',
    full_name='Matt Perez',
    primary_processing_id=processing.id
)
account = Payload::Customer.create(
    email: 'matt.perez@example.com',
    full_name: 'Matt Perez'
)
<?php
$account = Payload\Customer::create(array(
    'email' => 'matt.perez@example.com',
    'full_name' => 'Matt Perez'
));
?>
pl.Customer.create({
    email: 'matt.perez@example.com',
    full_name: 'Matt Perez'
}).then(function(account){
})
var account = pl.Customer.create(new {
    email="matt.perez@example.com",
    full_name="Matt Perez"
});

Create a customer account is simple. Start creating an account of type customer and provide the customer’s email address and name.

If you have more than one processing account, you can specify the primary processing account for the customer by passing the primary_processing_id.

Once an account has been created, you can store the customer['id'] of the resulting Payload account.


Customer Checkout

<form action="/submit_payment" method="POST">
  <script src="https://payload.co/Payload.js"
    pl-client-key="client_key_AWcpDnNBB7oLfNqfQ6g66262"
    pl-amount="100.00"
    pl-description="Membership"
    pl-customer-id="{customer_id}">
  </script>
</form>

Once you’ve created a customer account, you can pass the customer_id to Checkout using the data-customer-id parameter.

This will load any stored payment methods and settings for that customer and allow them to update their payment options.


Automating Billing

Create a customer invoice

curl "https://api.payload.co/invoices/" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -d items[0][amount]=100 \
    -d items[0][description]=membership \
    -d customer_id="3bW9JMoqAIGhB3J4axyam"
invoice = pl.Invoice.create(
        items=[ pl.ChargeItem(amount=100, description="membership") ],
        customer_id=customer.id
    )
invoice = Payload::Invoice.create(
    items: [ Payload::ChargeItem( amount: 100, description: 'membership' ) ],
    customer_id: customer.id
)
<?php
$invoice = Payload\Invoice::create(array(
    'customer_id' => customer.id,
    'items' => array(
        new Payload\ChargeItem( 'amount' => 100, 'description' => 'membership' )
    )
));
?>
// Create a customer invoice
pl.Invoice.create({
        items: [
            new pl.ChargeItem({
                amount: 100,
                description: "membership"
            })
        ],
        customer_id: customer.id
    }).then(function(invoice) {
    })

var invoice = pl.Invoice.create(new {
        due_date=new Date(2019,5,1),
        items=new []{
            new pl.ChargeItem(new{amount=100, description="membership"})
        },
        customer_id=customer.id
    });

A key feature of customer accounts is being able to setup automated billing. With a customer account you can:

More information can be found in the Billing & Invoicing section.


Billing & Invoicing

Invoicing

Create an Invoice


curl "https://api.payload.co/invoices/" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -d type="bill" \
    -d due_date="2019-01-01" \
    -d processing_id="3bW9JMapnT7sw7neax7ui" \
    -d items[0][type]="item1" \
    -d items[0][amount]=29.99 \
    -d customer_id=3bW9JMoGYQul5fCIa9f8q
invoice = pl.Invoice.create(
    type='bill',
    processing_id='3bW9JMapnT7sw7neax7ui',
    due_date=datetime.date(2019,1,1),
    items=[
        pl.ChargeItem(type='item1', amount=29.99)
    ],
    customer_id='3bW9JMoGYQul5fCIa9f8q'
)
invoice = Payload::Invoice.create(
    type: 'bill',
    processing_id: 'AcOnw5PigJ4Ww43Fo',
    due_date: '2019-01-01',
    items: [
        Payload::ChargeItem.new(
            type: 'item1',
            amount: 29.99
        )
    ],
    customer_id='3bW9JMoGYQul5fCIa9f8q'
)
<?php
invoice = Payload\Invoice::create(array(
    'type' => 'bill',
    'processing_id' => '3bW9JMapnT7sw7neax7ui',
    'due_date' => '2019-01-01',
    'items' => array(
        new Payload\Item(array(
            'type' => 'item1',
            'amount' => 29.99
        ))
    ),
    'customer_id' => '3bW9JMoGYQul5fCIa9f8q'
));
?>
pl.Invoice.create({
    type: 'bill',
    processing_id: '3bW9JMapnT7sw7neax7ui',
    due_date: '2019-01-01',
    items: [
        new pl.ChargeItem({
            type: 'item1',
            amount: 29.99
        })
    ],
    customer_id: '3bW9JMoGYQul5fCIa9f8q'
})
var invoice = pl.Invoice.create(new {
    type="bill",
    processing_id="3bW9JMapnT7sw7neax7ui",
    due_date="2019-01-01",
    items=new[]{
        new pl.ChargeItem(new{
            type="item1",
            amount=29.99
        })
    },
    customer_id="3bW9JMoGYQul5fCIa9f8q"
});

Invoicing is a simple way to create and track orders, and send payment requests. At the core, an invoice has a due date, an associated processing account for routing funds, and line item charges. You can also assign a customer to an invoice.

Line items can be positive or negative values and can be either a charge or a payment type. A charge type refers to an incurred amount by the biller. A payment type should be reserved for payments from the customer only.


Pay an Invoice

curl -s "https://api.payload.co/transactions" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE:\
    -X POST \
    -d account_id=3bW9JND5iKnAlOYn9u82q \
    -d amount=100 \
    -d type=payment \
    -d allocations[0][invoice_id]=3bW9JND5iKnAlOYn9u82q
invoice = pl.Invoice.get('3bW9JND5iKnAlOYn9u82q')

if invoice.status != 'paid':
    payment = pl.Payment.create(
        amount=invoice.amount_due,
        customer_id=invoice.customer_id,
        allocations=[
            pl.PaymentItem( invoice_id=invoice.id )
        ]
    ))
invoice = Payload::Invoice.get('3bW9JND5iKnAlOYn9u82q')

if invoice.status != 'paid'
    payment = Payload::Payment.create(
        amount: invoice.amount_due,
        customer_id: invoice.customer_id,
        allocations: [
            Payload::PaymentItem.new(
                invoice_id: invoice.id
            )
        ]
    )
end
<?php
$invoice = Payload\Invoice::get('3bW9JND5iKnAlOYn9u82q');

if ( invoice.status != 'paid' ) {
    $payment = Payload\Payment::create(array(
        'amount' => $invoice.amount_due,
        'customer_id' => $invoice.customer_id,
        'allocations' => array(
            Payload\PaymentItem::new(array(
                invoice_id=>$invoice.id
            ))
        )
    ));
}
?>
pl.Invoice.get('3bW9JND5iKnAlOYn9u82q')
    .then(function( invoice ){
        if ( invoice.status != 'paid' ) {
            pl.Payment.create({
                    amount: invoice.amount_due,
                    customer_id: invoice.customer_id,
                    allocations: [
                        new pl.PaymentItem({
                            invoice_id: invoice.id,
                        })
                    ]
                })
        }
    })
var invoice = pl.Invoice.get("3bW9JND5iKnAlOYn9u82q");

if ( invoice.status != "paid" ) {
    var payment = pl.Payment.create(new {
        amount=invoice.amount_due,
        customer_id=invoice.customer_id,
        allocations=new[]{
            new pl.PaymentItem(new{
                invoice_id=invoice.id
            })
        }
    });
}

To pay invoice, you can create a payment object with a nested payment line item within the allocations nested array. This will allocate the transaction to the invoice, subtracting from any balance due on that invoice.

If you’re using Checkout, you can pass the invoice id to the checkout instance and it will automatically allocate any successful payments.


Billing Schedules

Create a Billing Schedule

Setup a Billing Schedule

curl "https://api.payload.co/billing_schedules/" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -d start_date="2019-01-01" \
    -d end_date="2019-12-31" \
    -d recurring_frequency="monthly" \
    -d type="subscription" \
    -d processing_id="3bW9JMapnT7sw7neax7ui" \
    -d charges[0][type]=option_1 \
    -d charges[0][amount]=39.99 \
    -d customer_id=3bW9JMorTV1q6mXkkXUTg
billing_schedule = pl.BillingSchedule.create(
    start_date=datetime.date(2019, 1, 1),
    end_date=datetime.date(2019, 12, 31),
    recurring_frequency='monthly',
    type='subscription',
    processing_id='3bW9JMapnT7sw7neax7ui',
    charges=[
        pl.BillingCharge(type='option_1', amount=39.99)
    ],
    customer_id='3bW9JMorTV1q6mXkkXUTg'
)
billing_schedule = Payload::BillingSchedule.create(
    start_date: '2019-01-01',
    end_date: '2019-12-31',
    recurring_frequency: 'monthly',
    type: 'subscription',
    processing_id: '3bW9JMapnT7sw7neax7ui',
    charges: [
        Payload::BillingCharge.new(
            type: 'option_1',
            amount: 39.99
        )
    ],
    customer_id: '3bW9JMorTV1q6mXkkXUTg'
)
<?php
$billing_schedule = Payload\BillingSchedule::create(array(
    'start_date' => '2019-01-01',
    'end_date' => '2019-12-31',
    'recurring_frequency' => 'monthly',
    'type' => 'subscription',
    'processing_id' => '3bW9JMapnT7sw7neax7ui',
    'charges' => array(
        new Payload\BillingCharge(array(
            'type' => 'option_1',
            'amount' => 39.99
        ))
    ),
    'customer_id' => '3bW9JMorTV1q6mXkkXUTg'
));
?>
pl.BillingSchedule.create({
    start_date: '2019-01-01',
    end_date: '2019-12-31',
    recurring_frequency: 'monthly',
    type: 'subscription',
    processing_id :  '3bW9JMapnT7sw7neax7ui',
    charges: [
        new pl.BillingCharge({
            type: 'option_1',
            amount: 39.99
        })
    ],
    customer_id: '3bW9JMorTV1q6mXkkXUTg'
}).then(function(billing_schedule) {
})
var billing_schedule = pl.BillingSchedule.create(new {
    start_date="2019-01-01",
    end_date="2019-12-31",
    recurring_frequency="monthly",
    type="subscription",
    processing_id="3bW9JMapnT7sw7neax7ui",
    charges=new[]{
        new pl.BillingCharge(new{
            type="option_1",
            amount=39.99
        })
    },
    customer_id="3bW9JMorTV1q6mXkkXUTg"
});

If you have a preset or recurring billing schedule, you can use the billing schedule object to create and manage advanced billing settings. You can define charges, start dates, frequencies, and more, as well as enable automatic billing of invoices to a customer.

Invoices will be automatically generated based on your billing schedule’s recurring_frequency, with Line Items that correspond with the Billing Charges in your charges array.

For more information on integrating Billing Schedules, check out the Subscription Tutorial.


Specify Billing Frequency

Updating a Billing Frequency

curl "https://api.payload.co/billing_schedules/{id}" \
  -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
  -X PUT \
  -d recurring_frequency="bimonthly" \
  -d bimonthly[first_billing_day]=1 \
  -d bimonthly[second_billing_day]=15
billing_schedule.update(
  recurring_frequency='annually'
  annually={
    'billing_month': 12,
    'billing_day': 31
  }
)
billing_schedule.update(
    recurring_frequency: 'monthly'
)
<?php
$billing_schedule->update(array( 'recurring_frequency'=>'quarterly' ));
?>
billing_schedule.update({
  recurring_frequency: 'quarterly',
  quarterly: {
    q1: {
      billing_month: 2,
      billing_day:28
    },
    q2: {
      billing_month: 5,
      billing_day: 31
    },
    q3: {
      billing_month: 8,
      billing_day: 31
    },
    q4: {
      billing_month: 11,
      billing_day: 30
    }
  }
}).then(function(update) {
  // Handle Billing Schedule update
})
account.update(new { recurring_frequency="bimonthly" });

Billing schedules can run daily, weekly, biweekly (every two weeks), bimonthly (twice a month), monthly, quarterly, or annually. If the recurring_frequency is set to bimonthly, monthly, quarterly, or annually, the billing day(s) and/or month(s) can be adjusted by updating the corresponding nested object.

Within the bimonthly, monthly, quarterly, and annually objects, the fields are integers that represent the day(s) and/or month(s) on which billing will occur. In the example below, billing will occur on the 12th of every month, starting with the first 12th of the month after the start_date, and ending with the last 12th of the month before the end_date.

'monthly': {
  'billing_day': 12
}

Default Behavior

Recurring billing will occur on the following days if values are not provided:

daily: Every day beginning on the start_date

weekly: Every seven days, beginning on the start_date

biweekly: Every fourteen days, beginning on the start_date

Note that automatic invoice generation does not occur for partial billing periods.

bimonthly default value
first_billing_day The day the Billing Schedule was created, or 14 days before
second_billing_day The day the Billing Schedule was created, or 14 days after

The default values for the bimonthly billing days are set dynamically based on the day of the month on which the Billing Schedule was created. By default they will always be 14 days apart, the first_billing_day will always be lower, and the second_billing_day will never be 29, 30, or 31.

For example, if the Billing Schedule was created on the 22nd of the month, the first_billing_day will be 8, and the second_billing_day will be 22. If the Billing Schedule was created on the 3rd of the month, the first_billing_day will be 3, and the second_billing_day will be 17.

monthly default value
billing_day The day the Billing Schedule was created
quarterly default value
q1[billing_day] and q1[billing_month] 1 and 1 (the 1st of January)
q2[billing_day] and q2[billing_month] 1 and 4 (the 1st of April)
q3[billing_day] and q3[billing_month] 1 and 7 (the 1st of July)
q4[billing_day] and q4[billing_month] 1 and 10 (the 1st of October)

By default, quarterly billing will occur on the first day of each quarter.

annually default value
billing_day The day the Billing Schedule was created
billing_month The month the Billing Schedule was created

Edge Cases

For the bimonthly, monthly, quarterly, and annually recurring frequencies, billing can be set to occur on any day of a given month, including the 29th - 31st.

For months with fewer than 31 days, billing will occur on the last available day of that month.

This means that in April, all billing for the 30th and the 31st of the month will occur on April 30th. In February, all billing for the 28th-31st of the month will occur on the 28th.

In leap years, all billing for the 29th-31st of February will occur on February 29th.


Enable Automatic Payments

If a customer has a default_billing_method_id set on their profile, this payment method will be automatically charged on the due date of any invoice they are assigned to.


Mobile Card Reader

curl -s "https://api.payload.co/readers" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE:
card_reader = pl.CardReader.select().all().first()
print(card_reader.json())
card_reader = Payload::CardReader.select(
    wifi_details: {'status': 'connected'}).first
puts card_reader.json()
<?php
$card_reader = Payload\CardReader::select()[0];
echo($card_reader.json());
?>
pl.CardReader.select()
    .then(function( card_readers ){
        console.log(card_readers[0].json())
    })
var card_reader = pl.CardReader.select().all()[0];

card_reader.json();
{
    "id": "7IpDlK8yqRnJm7rQhHW892",
    "object": "reader",
    "created_at": "Mon, 27 May 2019 00:11:13 GMT",
    "modified_at": "Mon, 27 May 2019 00:11:13 GMT",
    "name": "eDynamo-B49BC7E",
    "processing_id": null,
    "serial_num": "B49BC7E042319AA",
    "type": "mgtk_edynamo"
}

Our integrated card reader has a simple interface to help seamlessly facilitate your in-person payments through the /readers API resource.

The mobile reader can be used out of the box with our mobile Android and iOS SDKs.

Features

Supported Platforms


Android
>=21

iOS
>=10

View the Card Reader SDK Docs


Webhook Triggers

Registering a Webhook

curl "https://api.payload.co/webhooks/" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -d trigger="payment" \
    -d url="https://yourdomain.com/path/to/webhook/handler"
webhook = pl.Webhook.create(
    trigger='payment',
    url='https://yourdomain.com/path/to/webhook/handler'
)
webhook = Payload::Webhook.create(
    trigger: 'payment',
    url: 'https://yourdomain.com/path/to/webhook/handler'
)
<?php
$webhook = Payload\Webhook::create(array(
    'trigger' => 'payment',
    'url' => 'https://yourdomain.com/path/to/webhook/handler'
));
?>
pl.Webhook.create({
    trigger: 'payment',
    url: 'https://yourdomain.com/path/to/webhook/handler'
}).then(function(webhook){})
var webhook = pl.Webhook.create(new {
    trigger="payment",
    url="https://yourdomain.com/path/to/webhook/handler"
});

Example Trigger Request

POST https://yourdomain.com/path/to/webhook/handler

Example Trigger Payload

{
    "object": "webhook_trigger",
    "trigger": "payment",
    "triggered_on": {
        "id": "3bW9JN4BVk3wU0ZZQs2Ay",
        "type": "payment",
        "object": "transaction",
    }
}

Webhooks can be used to monitor events in real-time by initiating a http request to any specified url providing an instant notification of that event.

When a trigger occurs, a POST request will be made to the webhook URL with details of the object that triggered the webhook. The http response code from the request is stored in the Webhook logs for simple auditing of the triggered requests.

The available triggers are shown below.

Triggers

Name Description
payment Any payment that gets initiated
refund Any refund that gets initiated
void Any payment that gets voided
automatic_payment Any payment that is initiated by automatic billing
decline Any payment that gets declined
chargeback Any chargebacks that get issued against the account
chargeback_reversal Any chargebacks that get overturned
bank_account_reject Any bank payment that get rejected by the bank
processing_status Any change to the activation status of a processing account

Reporting & Analytics

import payload as pl
from payload import attr

Custom reporting & analytics is simple by utilizing our query language combined with the aggregate response value modifier functions and group by capabilities.

Using our software libraries ARM (API Relational Model) design, constructing complex reporting queries is simple and intuitive.

Example Queries

Monthly Payments by Card Type

results = pl.Transaction.select(
        attr.completed_date.month(),
        attr.completed_date.year(),
        attr.payment_method.card_type.countbyval()
    ).filter_by(
        attr.status == 'processed',
        attr.completed_date.year() == 2019,
        attr.completed_date.month() <= 6
    ).group_by(
        attr.completed_date.month(),
        attr.completed_date.year()
    ).all()
pl.Transaction.select(
        attr.completed_date.month(),
        attr.completed_date.year(),
        attr.payment_method.card_type.countbyval()
    ).filter_by(
        attr.status.eq('processed'),
        attr.completed_date.year().eq(2019),
        attr.completed_date.month().eq(6)
    ).group_by(
        attr.completed_date.month(),
        attr.completed_date.year()
    ).then(function(results) {
    })
var results = pl.Transaction.select(
        attr.completed_date.month(),
        attr.completed_date.year(),
        attr.payment_method.card_type.countbyval()
    ).filter_by(
        attr.status.eq("processed"),
        attr.completed_date.year().eq(2019),
        attr.completed_date.month().eq(6)
    ).group_by(
        attr.completed_date.month(),
        attr.completed_date.year()
    ).all();
year(completed_date) month(completed_date) count(visa) count(mc) count(amex)
2019 1 627 170 68
2019 2 890 286 154
2019 3 1590 276 243
2019 4 1326 325 304
2019 5 1654 365 241
2019 6 1891 479 302

Average Volume by Day of Week

results = pl.Transaction.select(
        pl.attr.completed_date.dayofweek(),
        pl.attr.amount.avgsum()
    ).filter_by(
        pl.attr.status == 'complete',
        pl.attr.completed_date.year() == 2019
    ).group_by(
        pl.attr.completed_date.dayofweek()
    ).all()
pl.Transaction.select(
        pl.attr.completed_date.dayofweek(),
        pl.attr.amount.avgsum()
    ).filter_by(
        pl.attr.status.eq('complete'),
        pl.attr.completed_date.year().eq(2019)
    ).group_by(
        pl.attr.completed_date.dayofweek()
    ).then(function(results) {
    })
var results = pl.Transaction.select(
        pl.attr.completed_date.dayofweek(),
        pl.attr.amount.avgsum()
    ).filter_by(
        pl.attr.status.eq("complete"),
        pl.attr.completed_date.year().eq(2019)
    ).group_by(
        pl.attr.completed_date.dayofweek()
    ).all();
dayofweek(completed_date) avgsum(amount)
sunday 24960.22
monday 8060.74
tuesday 15732.97
wednesday 15732.97
thursday 26703.59
friday 29253.64
saturday 25357.85

Unified Payout & Ledger

Transaction Ledger

The transaction ledger holds the records of all associated payment activity and how the relate, like refunds of a payment. Each transaction has a nested list of ledger entries relative to them.


Reading the Ledger Records

curl "https://api.payload.co/transactions" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -d "fields[]=*" \
    -d "fields[]=ledger"
payment = pl.Payment.select( pl.attr.ledger, *pl.Transaction )
    .get('3bW9JN8jkM9mP3qQCO5mC')
payment = Payload::Payment.select( '*', 'ledger' )
    .get('3bW9JN8jkM9mP3qQCO5mC')
payment = Payload\Payment::select(array(
    '*', 'ledger'
)).get('3bW9JN8jkM9mP3qQCO5mC')
pl.Payment.select('*', pl.attr.ledger)
    .get('3bW9JN8jkM9mP3qQCO5mC')
    .then(function(trans) {
    })
var trans = pl.Payment.filter_by( "*", pl.attr.ledger )
    .get("3bW9JN8jkM9mP3qQCO5mC");

The nested ledger list can be included in the response by requesting the ledger attribute be part of the response.


{
  "id": "3bW9JN4OPJXdUyrK5VZQG",
  "object": "transaction",
  "amount": 29.99,
  "created_at": "2019-01-01 21:41:04",
  "payment_method_id": "3bW9JMoT2CKw8DQ1yFyG8",
  "status": "processed",
  "type": "payment",
  "ledger": [{
    "amount": -29.99,
    "assoc_transaction_id": "3bW9JN8cF50sSYDtI5X0a",
    "timestamp": "2019-01-04 18:30:09",
    "entry_type": "deposit"
  },{
    "amount": -29.99,
    "assoc_transaction_id": "3bW9JN8cutWRm2iYnhjaS",
    "timestamp": "2019-01-10 09:52:29",
    "entry_type": "refund"
  },{
    "amount": 29.99,
    "assoc_transaction_id": "3bW9JN8dAmVVEkM5guwca",
    "timestamp": "2019-01-10 18:30:23",
    "entry_type": "reversal"
  }]
}

Ledger entries can be either positive or negative depending on whether the associated transaction is a debit or a credit relative to the parent transaction.

The ledger entry_type refers to the associated transaction type.

In the example you’ll see a payment that was deposited but was later refunded. Since the payment had already been deposited, a reversal transaction was initiated to rebalance the ledger.


Unified Payout

Payout Batching

All transaction, regardless of whether the payment was made with a bank account, Visa, MasterCard, Discover, or American Express, are batched into a single unified deposit, daily.


List of Deposited Payments

curl "https://api.payload.co/transactions" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -d "fields=*,ledger" \
    -d "type=deposit" \
    -d "account_id=$processing_id"
trans = pl.Transaction.select(
        pl.attr.ledger,
        *pl.Transaction
    ).filter_by(
        type='deposit',
        account_id=processing_account.id
    )
trans = Payload::Transaction.select( type: 'deposit',
    account_id: processing_account.id, fields: '*,ledger' )
trans = Payload\Transaction::select(array(
    'type'=>'deposit',
    'account_id'=>$processing_account->id,
    'fields'=>'*,ledger'
))
payload.Transaction.select({
    'type': 'deposit',
    'account_id': processing_account.id,
    'fields': '*,ledger'
)).then(function(trans) {
})
var trans = pl.Transaction.select(
        "*", pl.attr.ledger
    ).filter_by(new{
        account_id=processing_account.id,
        type="deposit"
    });

To nested ledger list of a deposit will include the list of associated payments with a deposit.


Security & Compliance

Data Security & PCI

Our platform is certified to the highest level of PCI for data security, and we go beyond the industry standards at every level. From our above grade zero-access secure vault to our rotating encryption mechanism utilizing cryptographic splitting, this is not your every-day tokenization.

Tokenization

# Example of passing card details to be stored securely
payment_method = pl.Card.create(
    full_name='John Smith',
    card_number='4242424242424242',
    expiration_date='05/22',
    card_code='123'
)
print(payment_method.id)
# Returns the id of the tokenized payment details
// Example of passing card details to be stored securely
pl.Card.create(
    full_name='John Smith',
    card_number='4242424242424242',
    expiration_date='05/22',
    card_code='123'
).then(function(payment_method) {
    console.log(payment_method.id)
})
// Returns the id of the tokenized payment details
// Example of passing card details to be stored securely
var payment_method = pl.Card.create(new {
    full_name="John Smith",
    card_number="4242 4242 4242 4242",
    expiration_date="05/22",
    card_code="123"
});

Console.WriteLine(payment_method.id);
// Returns the id of the tokenized payment details

Take advantage of our secure, unidirectional, financial data security vault. Often referred to as tokenization, our platform handles the security and storage of your sensitive financial data taking the burden off your hands.


Client-Side Tools

<!-- Checkout Modal -->
<form action="/submit_payment" method="POST">
  <script src="https://payload.co/Payload.js"
    pl-client-key="client_key_AWcpDnNBB7oLfNqfQ6g66262"
    pl-amount="1000.00">
  </script>
</form>
<!-- Secure Input -->
<script src="https://payload.co/Payload.js"></script>

<form action="/submit_card_data" method="POST">
  <input pl-secure-input="card_number"/>
</form>

To keep your servers out of the scope of any PCI and data security requirements, our client-side toolkits make it easy to secure all sensitive financial data encrypted on the client’s machine and routed directly to us keeping you out of any data security liability.

UI Toolkit Options:


Payment & Risk Monitoring

We recognize that your business has its own cash flow requirements, and we designed our dynamic risk management technology to support your processing needs instead of industry-standard date or time-based limits. We are here to help you run your business the way you want to - with the simplest and most flexible payment platform, so you won’t need to design around typical payment processing limitations.

Payment Analysis

Our payment-by-payment real-time monitoring utilizes data-driven behavioral machine learning that looks at data points in over 150 categories across billions of dollars in processing volume. These industry-specific risk models categorize behavior by what’s standard for your operating space, not just generalized to our platform.

Flagged Transaction

results = pl.Transaction.select(
        attr.id,
        attr.risk_score
    ).filter_by(risk_flag='in_review')\
    .all()
pl.Transaction.select(
        attr.id,
        attr.risk_score
    ).filter_by(risk_flag='in_review')
    .then(function(results){
    })
var results = pl.Transaction.select(
        attr.id,
        attr.risk_score
    ).filter_by(new { risk_flag="in_review" })
    .all();

You can retrieve and review the results through the API or dashboard. Each transaction has a risk score between -1 and 1, along with a flagged status.

You can query your flagged transactions through the API or review them on our dashboard. Using the API or dashboard you can update the status of flagged transactions to either accept or reject.

Settings & Controls

Controlling your risk settings is simple. Through our dashboard you can configure your risk threshold for automatically flagging transactions as well as enable and configure other data validation options.

Data Validation Settings:


Object Reference

Accounts

https://api.payload.co/accounts

Nested Objects

https://api.payload.co/accounts/{id}/payment_methods

Example

{
  "id": "vcHGFCnfFLUiCvsSTHjYqGE4",
  "object": "account",
  "attrs": {},
  "created_at": "2019-11-22 14:14:07",
  "description": "string",
  "email": "email@address.com",
  "modified_at": "2019-11-22 14:14:07",
  "name": "string",
  "parent_org_id": "YtCDKs3MncM96DjAiko1FWbP",
  "payment_methods": [],
  "phone_number": "(123) 456-7890",
  "primary_processing_id": "JddKd5DJze9qRtTHYEMeT6ww",
  "transaction_limit": 994.78,
  "type": "customer",
  "processing": {
    "industry": "string",
    "status": "pending",
    "settings": {
      "id": "Iol59h8ZfbVIEzdcWHB2GNEz",
      "bank_account_conv_fee_alloc": 0,
      "bank_account_processing_enabled": false,
      "bank_account_trans_cost": 1.25,
      "bank_account_trans_rate": 0,
      "batch_fee": 984.51,
      "billing_preference": "netted_daily",
      "card_processing_enabled": false,
      "change_fee": 720.89,
      "chargeback_fee": 864.01,
      "credit_conv_fee_alloc": 0,
      "credit_trans_cost": 0.1,
      "credit_trans_rate": 0.0275,
      "debit_conv_fee_alloc": 0,
      "debit_trans_cost": 0.1,
      "debit_trans_rate": 0.0275,
      "minimum_bill": 875.85,
      "monthly_processing_fee": 25,
      "nabu_fee": 850.7,
      "pci_fee": 814.69,
      "pricing": "flat_rate",
      "processing_type": "payfac",
      "retrieval_fee": 554.93
    }
  }
}
Attributes Description
id
string readonly
Object ID
object
string readonly
Value: account
attrs
json
Custom object attributes
created_at
datetime readonly
Timestamp object was created
description
string
Optional description of the account
email
email required
Email address for the account
modified_at
datetime readonly
Timestamp object was last updated
name
string required
Name for the account, either a person or company name
parent_org_id
id
Specify the parent org for an account
payment_methods
list
Array of associated Payment Method objects
phone_number
phone
Phone number for the account
primary_processing_id
id
Specify the primary processing account for a customer
transaction_limit
number readonly
The account’s transaction limit
type
string required
Values: customer processing
processing:  
industry
string required
Primary processing industry
status
string readonly: SessionPermission
Status of the processing account activation
settings:  
id
string readonly
Object ID
bank_account_conv_fee_alloc
number required
Percentage of bank account fee charged as a convenience
bank_account_processing_enabled
bool required
If enabled, bank payments allowed on the account
bank_account_trans_cost
number readonly
Per bank account transaction fixed cost
bank_account_trans_rate
number readonly
Per bank account transaction percentage rate
batch_fee
number required
None
billing_preference
string required
Values: netted_daily billed_monthly
card_processing_enabled
bool required
If enabled, card payments allowed on the account
change_fee
number required
None
chargeback_fee
number required
None
credit_conv_fee_alloc
number required
Percentage of credit card fee charged as a convenience
credit_trans_cost
number readonly
Per credit card transaction fixed cost
credit_trans_rate
number readonly
Per credit card transaction percentage rate
debit_conv_fee_alloc
number required
Percentage of debit card fee charged as a convenience
debit_trans_cost
number readonly
Per debit card transaction fixed cost
debit_trans_rate
number readonly
Per debit card transaction percentage rate
minimum_bill
number required
None
monthly_processing_fee
number readonly
Fixed monthly fee per processing account
nabu_fee
number required
None
pci_fee
number required
None
pricing
string required
Values: flat_rate tiered interchange
processing_type
string readonly: SessionPermission
Values: payfac mor mor_tsys
retrieval_fee
number required
None
 
 

Transactions

https://api.payload.co/transactions

Nested Objects

https://api.payload.co/transactions/{id}/payment_method

https://api.payload.co/transactions/{id}/ledger

https://api.payload.co/transactions/{id}/allocations

https://api.payload.co/transactions/{id}/reader

https://api.payload.co/transactions/{id}/customer

Example

{
  "id": "1PRMnFUvIe2X3vInEldNi1E44",
  "object": "transaction",
  "amount": 164.71,
  "attrs": {},
  "created_at": "2019-11-22 14:14:07",
  "customer_id": "1I39Qga6ZCKZg9nbBejEfi57B",
  "description": "string",
  "fee": 1.32,
  "funding_status": "pending",
  "modified_at": "2019-11-22 14:14:07",
  "order_number": "string",
  "payment_method": {},
  "payment_method_id": "gxNCnxM7qeg8BD7XB7smoysB",
  "processing_id": "1zoyBosUW9pWLX97am0b9lBgj",
  "reader_id": "1LPTw0itqocS8hmWjA4nh3gnX",
  "risk_flag": "in_review",
  "risk_score": 131.14,
  "source": "keyed",
  "status": "processing",
  "status_code": "string",
  "status_message": "string",
  "type": "payment"
}
Attributes Description
id
string readonly
Object ID
object
string readonly
Value: transaction
amount
number readonly: update
Transaction amount
attrs
json
Custom object attributes
created_at
datetime readonly
Timestamp object was created
customer_id
id readonly: update
ID of associated Customer object
description
string
Description of the transaction
fee
number readonly
Processing fee
funding_status
string readonly
Values: pending captured batched refunded reversed
modified_at
datetime readonly
Timestamp object was last updated
order_number
string
None
payment_method
object
Associated Payment Method object
payment_method_id
id readonly: update
ID of the associated Payment Method object
processing_id
id readonly: update
ID of the associated Processing Account object
reader_id
id readonly: update
None
risk_flag
string readonly
Values: in_review allowed denied
risk_score
number readonly
Risk score between -1 to 1
source
string readonly: update
Values: keyed swipe emv emv_quickchip nfc
status
string
Values: processing processed declined voided rejected
status_code
string readonly
Code detailing the reason for the transaction status
status_message
string readonly
Human-readable status description
type
string readonly: update
Values: payment deposit reversal refund chargeback chargeback_reversal

Transaction Ledger

https://api.payload.co/transaction_ledgers

Example

{
  "id": "1VwR7D8FSeeIwLBz1MCrkHEYE",
  "object": "transaction_ledger",
  "amount": 673.5,
  "assoc_transaction_id": "hRP6J5Z5k4Pka90mbrRj11Ki",
  "attrs": {},
  "created_at": "2019-11-22 14:14:07",
  "entry_type": "string",
  "modified_at": "2019-11-22 14:14:07",
  "transaction_id": "TDdzjiVwiGE1SK9cDY3vRy3b"
}
Attributes Description
id
string readonly
Object ID
object
string readonly
Value: transaction_ledger
amount
number
Amount of the entry
assoc_transaction_id
id required
ID of the associated Transaction object
attrs
json
Custom object attributes
created_at
datetime readonly
Timestamp object was created
entry_type
string readonly
Resulting transfer type
modified_at
datetime readonly
Timestamp object was last updated
transaction_id
id required
ID of the Transaction object

Payment Methods

https://api.payload.co/payment_methods

Nested Objects

https://api.payload.co/payment_methods/{id}/legal_entity

https://api.payload.co/payment_methods/{id}/processing_agreement

Example

{
  "id": "cOxRrdJNPMd6rhUxnMANhYCJ",
  "object": "payment_method",
  "account_holder": "string",
  "account_id": "niJz60vDN8ya5BMnHWbxKKBg",
  "attrs": {},
  "created_at": "2019-11-22 14:14:07",
  "default_payment_method": true,
  "description": "string",
  "legal_entity": {},
  "modified_at": "2019-11-22 14:14:07",
  "phone_number": "(123) 456-7890",
  "processing_agreement": {},
  "type": "card",
  "bank_account": {
    "account_class": "personal",
    "account_number": "numeric",
    "account_type": "checking",
    "routing_number": "numeric"
  },
  "billing_address": {
    "city": "string",
    "postal_code": "numeric",
    "state_province": "string",
    "street_address": "string",
    "unit_number": "string"
  },
  "card": {
    "card_brand": "american_express",
    "card_number": "numeric",
    "card_type": "credit",
    "expiry": "expiry"
  }
}
Attributes Description
id
string readonly
Object ID
object
string readonly
Value: payment_method
account_holder
string
Name of the account holder
account_id
id
ID of the associated Account object
attrs
json
Custom object attributes
created_at
datetime readonly
Timestamp object was created
default_payment_method
bool
If enabled, this method can be used as the default for the account
description
string readonly
A readable description for the payment method
legal_entity
object
Associated Legal Entity object
modified_at
datetime readonly
Timestamp object was last updated
phone_number
phone
Account holder’s phone number
processing_agreement
object
Associated Processing Agreement object
type
string required
Values: card bank_account
bank_account:  
account_class
string readonly: update
Values: personal business
account_number
numeric readonly: update
Bank account number
account_type
string readonly: update
Values: checking savings
routing_number
numeric readonly: update
Bank routing number for the account
 
billing_address:  
city
string
City of the company
postal_code
numeric required
Postal code of the billing address
state_province
string
State of the billing address
street_address
string
Street address of the billing address
unit_number
string
Unit number of the billing address
 
card:  
card_brand
string readonly
Values: american_express visa discover mastercard opticard
card_number
numeric readonly: update
Credit/Debit card number
card_type
string readonly: SessionPermission
Values: credit debit gift
expiry
expiry required
Expiration date of the card
 

Billing Schedules

https://api.payload.co/billing_schedules

Nested Objects

https://api.payload.co/billing_schedules/{id}/invoices

https://api.payload.co/billing_schedules/{id}/charges

Example

{
  "id": "1g7OBJRt2kV2fBtst0SSzUHQg",
  "object": "billing_schedule",
  "attrs": {},
  "charges": [],
  "created_at": "2019-11-22 14:14:08",
  "customer_id": "k8W0ZZyASHeSvnWtNPIjN0Ui",
  "description": "string",
  "end_date": "2019-11-22",
  "invoices": [],
  "modified_at": "2019-11-22 14:14:08",
  "processing_id": "vnpKSXPe8gT6sc6Xcw12iTn4",
  "recurring_frequency": "daily",
  "start_date": "2019-11-22",
  "type": "string",
  "bimonthly": {
    "first_billing_day": 8,
    "second_billing_day": 22
  },
  "monthly": {
    "billing_day": 22
  },
  "quarterly": {
    "q1": {
      "billing_day": 1,
      "billing_month": 1
    },
    "q2": {
      "billing_day": 1,
      "billing_month": 4
    },
    "q3": {
      "billing_day": 1,
      "billing_month": 7
    },
    "q4": {
      "billing_day": 1,
      "billing_month": 10
    }
  },
  "annually": {
    "billing_day": 22,
    "billing_month": 11
  },
}
Attributes Description
id
string readonly
Object ID
object
string readonly
Value: billing_schedule
attrs
json
Custom object attributes
charges
list
Array of associated Billing Charge objects
created_at
datetime readonly
Timestamp object was created
customer_id
id required
ID of the associated Customer Account object
description
string
Billing Description
end_date
date
End date of the billing schedule
invoices
list
Array of associated Invoice objects
modified_at
datetime readonly
Timestamp object was last updated
processing_id
id required
ID of associated Processing Account object
recurring_frequency
string
Values: daily weekly biweekly bimonthly monthly quarterly annually
start_date
date
Start date of the billing schedule
type
string required
Arbitrary type classification
bimonthly:  
first_billing_day
int
Values: 1-31
second_billing_day
int
Values: 1-31
monthly:  
billing_day
int
Values: 1-31
quarterly:  
q1:  
billing_day
int
Values: 1-31
billing_month
int
Values: 1 2 3
q2:  
billing_day
int
Values: 1-31
billing_month
int
Values: 4 5 6
q3:  
billing_day
int
Values: 1-31
billing_month
int
Values: 7 8 9
q4:  
billing_day
int
Values: 1-31
billing_month
int
Values: 10 11 12
 
annually:  
billing_day
int
Values: 1-31
billing_month
int
Values: 1-12
 

Billing Charges

https://api.payload.co/billing_charges

Example

{
  "id": "1XiL8LWncJTw6gh94Xr8NxpnG",
  "object": "billing_charge",
  "amount": 835.71,
  "attrs": {},
  "billing_schedule_id": "grPVIAx01BD8nT1negvgOqhw",
  "created_at": "2019-11-22 14:14:07",
  "description": "string",
  "modified_at": "2019-11-22 14:14:07",
  "qty": 299,
  "total": 680.91,
  "type": "string"
}
Attributes Description
id
string readonly
Object ID
object
string readonly
Value: billing_charge
amount
number required
Amount of the charge
attrs
json
Custom object attributes
billing_schedule_id
id required
ID of the associated Billing Schedule object
created_at
datetime readonly
Timestamp object was created
description
string
Description of charge
modified_at
datetime readonly
Timestamp object was last updated
qty
int
Quantity of the item
total
number readonly
Total amount of charge
type
string
Arbitrary type classification

Invoices

https://api.payload.co/invoices

Nested Objects

https://api.payload.co/invoices/{id}/items

https://api.payload.co/invoices/{id}/processing_settings

https://api.payload.co/invoices/{id}/attachments

https://api.payload.co/invoices/{id}/customer

Example

{
  "id": "1BLYEzBQZ4CzEgTTJbdHd5S2",
  "object": "invoice",
  "amount_due": 973.78,
  "attachments": [],
  "attrs": {},
  "billing_schedule_id": "SYsAeIq3pcsMs6ZNu5q2XTRk",
  "created_at": "2019-11-22 14:14:07",
  "customer_id": "7IhmC7KFulBQ98e9XN2eGt5a",
  "description": "string",
  "due_date": "2019-11-22",
  "items": [],
  "modified_at": "2019-11-22 14:14:07",
  "paid_timestamp": "2019-11-22",
  "processing_id": "1XxG2dMXL0TDmYxjpnHwu8iFD",
  "processing_settings_id": "jaFhgh9No6QeSjt3fdXDm5bJ",
  "status": "pending",
  "total_due": 608.61,
  "total_paid": 379.61,
  "type": "string",
  "billing_contact": {
    "city": "string",
    "email": "string",
    "name": "string",
    "postal_code": "string",
    "state_province": "string",
    "street_address1": "string"
  }
}
Attributes Description
id
string readonly
Object ID
object
string readonly
Value: invoice
amount_due
number readonly
Remaining amount paid
attachments
list
Array of associated Invoice Attachment objects
attrs
json
Custom object attributes
billing_schedule_id
id
ID of the associated Billing Schedule object
created_at
datetime readonly
Timestamp object was created
customer_id
id required
ID of the associated Customer Account object
description
string
Description of the invoice
due_date
date required
Date the invoice is due
items
list required
Array of associated Line Item objects
modified_at
datetime readonly
Timestamp object was last updated
paid_timestamp
date readonly
Timestamp invoice was fully paid
processing_id
id required
ID of the associated Processing Account object
processing_settings_id
id readonly
ID of the processing settings object
status
string
Values: pending overdue partially_paid paid
total_due
number readonly
Total amount due
total_paid
number readonly
Total amount paid
type
string
Arbitrary type classification
billing_contact:  
city
string readonly
City of the billing contact
email
string readonly
Email of the billing contact
name
string readonly
Name of the billing contact
postal_code
string readonly
Zipcode of the billing contact
state_province
string readonly
State of the billing contact
street_address1
string readonly
Street address of the billing contact
 

Line Items

https://api.payload.co/line_items

Example

{
  "id": "1ZPUrTGwL0FXyiDUbnex776KW",
  "object": "line_item",
  "amount": 969.27,
  "attrs": {},
  "created_at": "2019-11-22 14:14:07",
  "description": "string",
  "entry_type": "charge",
  "incurred_date": "2019-11-22",
  "invoice_id": "1G4hKfbUp9qe6CjiuaMAQ2CBp",
  "modified_at": "2019-11-22 14:14:07",
  "qty": 294,
  "total": 227.76,
  "transaction_id": "20vr9SVIza9GcNrjpCiNXa4w6",
  "type": "string"
}
Attributes Description
id
string readonly
Object ID
object
string readonly
Value: line_item
amount
number required
Amount of line item
attrs
json
Custom object attributes
created_at
datetime readonly
Timestamp object was created
description
string
Description of invoice item
entry_type
string required
Values: charge payment
incurred_date
date
Date the item was incurred
invoice_id
id required
ID of the associated Invoice object
modified_at
datetime readonly
Timestamp object was last updated
qty
int
Quantity of item
total
number readonly
Total amount of line item
transaction_id
id
ID of the associated Transaction
type
string
Arbitrary type classification

https://api.payload.co/legal_entities

Nested Objects

https://api.payload.co/legal_entities/{id}/owners

Example

{
  "id": "2iJ3Nur672bIAz52rt9L0MTe",
  "object": "legal_entity",
  "attrs": {},
  "city": "string",
  "contact_email": "email@address.com",
  "contact_name": "string",
  "contact_title": "string",
  "created_at": "2019-11-22 14:14:07",
  "ein": "numeric",
  "legal_name": "string",
  "modified_at": "2019-11-22 14:14:07",
  "owners": [],
  "payment_method_id": "1X7mbe9azkiU9SaCyl5B9uqeX",
  "phone_number": "(123) 456-7890",
  "postal_code": "numeric",
  "start_date": "2019-11-22 14:14:07",
  "state_incorporated": "string",
  "state_province": "string",
  "street_address": "string",
  "type": "LIMITED_LIABILITY_COMPANY",
  "unit_number": "string",
  "website": "string"
}
Attributes Description
id
string readonly
Object ID
object
string readonly
Value: legal_entity
attrs
json
Custom object attributes
city
string required
City of the business
contact_email
email required
Email of primary contact
contact_name
string required
Name of primary contact
contact_title
string required
Title of primary contact
created_at
datetime readonly
Timestamp object was created
ein
numeric required
Tax ID of the entity
legal_name
string required
Legal name of the entity
modified_at
datetime readonly
Timestamp object was last updated
owners
list required
Array of associated Legal Entity Owner objects
payment_method_id
id readonly
ID of the Funding Method object
phone_number
phone required
Phone number of the business
postal_code
numeric required
Postal code of the business
start_date
datetime required
Start date of the business
state_incorporated
string required
State where the legal entity was incorporated
state_province
string required
State of the business
street_address
string required
Street address of the business
type
string required
Values: LIMITED_LIABILITY_COMPANY CORPORATION PUBLIC_CORPORATION PARTNERSHIP GOVERNMENT_AGENCY ASSOCIATION_ESTATE_TRUST TAX_EXEMPT_ORGANIZATION INDIVIDUAL_SOLE_PROPRIETORSHIP
unit_number
string
Unit number of the business
website
string
Website of the business

https://api.payload.co/legal_entity_owners

Example

{
  "id": "5nRW7fMayipL0nxvW0gaFBHL",
  "object": "legal_entity_owner",
  "attrs": {},
  "birth_date": "2019-11-22 14:14:08",
  "city": "string",
  "created_at": "2019-11-22 14:14:08",
  "email": "email@address.com",
  "full_name": "string",
  "legal_entity_id": "L36gr3PzaMtAwr8DjAbHvlMG",
  "modified_at": "2019-11-22 14:14:08",
  "ownership": 711.64,
  "phone_number": "(123) 456-7890",
  "postal_code": "numeric",
  "ssn": "numeric",
  "state_province": "string",
  "street_address": "string",
  "title": "string",
  "type": "string",
  "unit_number": "string"
}
Attributes Description
id
string readonly
Object ID
object
string readonly
Value: legal_entity_owner
attrs
json
Custom object attributes
birth_date
datetime required
Birth date of owner
city
string required
City of the owner
created_at
datetime readonly
Timestamp object was created
email
email required
Email address of owner
full_name
string required
Full name of owner
legal_entity_id
id readonly
ID of the associated Legal Entity object
modified_at
datetime readonly
Timestamp object was last updated
ownership
number required
Equity position in the company
phone_number
phone required
Phone number of the owner
postal_code
numeric required
Postal code of the owner
ssn
numeric required
Social security number of owner
state_province
string required
State of the owner
street_address
string required
Street address of the owner
title
string required
Title of owner at the company
type
string required
Type of owner
unit_number
string
Unit number of the owner

https://api.payload.co/payment_links

Nested Objects

https://api.payload.co/payment_links/{id}/processing_settings

https://api.payload.co/payment_links/{id}/attachments

https://api.payload.co/payment_links/{id}/customer

https://api.payload.co/payment_links/{id}/transaction

Example

{
  "id": "mWo3z4o9oK4kxFPKPShQL96L",
  "object": "payment_link",
  "additional_datafields": {},
  "amount": 307.06,
  "attachments": [],
  "attrs": {},
  "created_at": "2019-11-22 14:14:08",
  "customer_id": "u6iTHoaNwaEGNXiDXuDgETtw",
  "description": "string",
  "modified_at": "2019-11-22 14:14:08",
  "processing_id": "6RLfYUtmEleZKPsObHTvU3UH",
  "processing_settings_id": "HsWIP9MkYh2tL5KuP74CeYbo",
  "transaction_id": "1CmCD3sog4HXf0V1zgWUdvkPX",
  "type": "one_time",
  "url": "string",
  "billing_contact": {
    "city": "string",
    "email": "string",
    "name": "string",
    "phone": "string",
    "postal_code": "string",
    "state_province": "string",
    "street_address1": "string",
    "website": "string"
  }
}
Attributes Description
id
string readonly
Object ID
object
string readonly
Value: payment_link
additional_datafields
json
Specify additional data elements to be collected with the payment
amount
number
Total amount due
attachments
list
Array of associated Payment Link Attachment objects
attrs
json
Custom object attributes
created_at
datetime readonly
Timestamp object was created
customer_id
id
ID of the associated Customer Account object
description
string
Description of the payment
modified_at
datetime readonly
Timestamp object was last updated
processing_id
id required
ID of the associated Processing Account object
processing_settings_id
id readonly
ID of the processing settings object
transaction_id
id readonly
ID of the associated Transaction object
type
string
Values: one_time reusable
url
string readonly
The URL to be used by client(s) to make payments
billing_contact:  
city
string readonly
City of the billing contact
email
string readonly
Email of the billing contact
name
string readonly
Name of the billing contact
phone
string readonly
Email of the billing contact
postal_code
string readonly
Zipcode of the billing contact
state_province
string readonly
State of the billing contact
street_address1
string readonly
Street address of the billing contact
website
string readonly
Email of the billing contact
 

Orgs

https://api.payload.co/orgs

Nested Objects

https://api.payload.co/orgs/{id}/account_access

Example

{
  "id": "KAEdsrYS8iL4dXHzIPAprm0N",
  "object": "org",
  "attrs": {},
  "created_at": "2019-11-22 14:14:07",
  "industry": "string",
  "modified_at": "2019-11-22 14:14:07",
  "name": "string",
  "org_type": "string",
  "parent_org_id": "1CVUwapuXz0Y2wYsBHWCN0MTE",
  "phone_number": "(123) 456-7890",
  "primary_processing_id": "HKD0zodHyC15beVy8MTH6H1Y",
  "timezone": "string",
  "processing_settings": {
    "id": "qTZK0ECNu3vYuDHBtvPOxKSD",
    "bank_account_conv_fee_alloc": 0,
    "bank_account_processing_enabled": true,
    "bank_account_trans_cost": 1.25,
    "bank_account_trans_rate": 0,
    "batch_fee": 317.36,
    "billing_preference": "netted_daily",
    "card_processing_enabled": true,
    "change_fee": 109.21,
    "chargeback_fee": 828.13,
    "credit_conv_fee_alloc": 0,
    "credit_trans_cost": 0.1,
    "credit_trans_rate": 0.0275,
    "debit_conv_fee_alloc": 0,
    "debit_trans_cost": 0.1,
    "debit_trans_rate": 0.0275,
    "minimum_bill": 875.97,
    "monthly_processing_fee": 25,
    "nabu_fee": 464.91,
    "pci_fee": 834.92,
    "pricing": "flat_rate",
    "processing_type": "payfac",
    "retrieval_fee": 751.51
  }
}
Attributes Description
id
string readonly
Object ID
object
string readonly
Value: org
attrs
json
Custom object attributes
created_at
datetime readonly
Timestamp object was created
industry
string required
Primary processing industry
modified_at
datetime readonly
Timestamp object was last updated
name
string required
Name of the organization
org_type
string required
Type of organization
parent_org_id
id
Specify the parent org for an account
phone_number
phone
Phone number of organization
primary_processing_id
id
The primary processing account for the account
timezone
string
The primary timezone for the account
processing_settings:  
id
string readonly
Object ID
bank_account_conv_fee_alloc
number required
Percentage of bank account fee charged as a convenience
bank_account_processing_enabled
bool required
If enabled, bank payments allowed on the account
bank_account_trans_cost
number readonly
Per bank account transaction fixed cost
bank_account_trans_rate
number readonly
Per bank account transaction percentage rate
batch_fee
number required
None
billing_preference
string required
Values: netted_daily billed_monthly
card_processing_enabled
bool required
If enabled, card payments allowed on the account
change_fee
number required
None
chargeback_fee
number required
None
credit_conv_fee_alloc
number required
Percentage of credit card fee charged as a convenience
credit_trans_cost
number readonly
Per credit card transaction fixed cost
credit_trans_rate
number readonly
Per credit card transaction percentage rate
debit_conv_fee_alloc
number required
Percentage of debit card fee charged as a convenience
debit_trans_cost
number readonly
Per debit card transaction fixed cost
debit_trans_rate
number readonly
Per debit card transaction percentage rate
minimum_bill
number required
None
monthly_processing_fee
number readonly
Fixed monthly fee per processing account
nabu_fee
number required
None
pci_fee
number required
None
pricing
string required
Values: flat_rate tiered interchange
processing_type
string readonly: SessionPermission
Values: payfac mor mor_tsys
retrieval_fee
number required
None
 

Webhooks

https://api.payload.co/webhooks

Nested Objects

https://api.payload.co/webhooks/{id}/logs

Example

{
  "id": "1kR6HwNYdPEcNok2xRTrnA4Dt",
  "object": "webhook",
  "attrs": {},
  "created_at": "2019-11-22 14:14:08",
  "modified_at": "2019-11-22 14:14:08",
  "trigger": "bank_account_reject",
  "url": "https://example.com/bank_account_reject"
}
Attributes Description
id
string readonly
Object ID
object
string readonly
Value: webhook
attrs
json
Custom object attributes
created_at
datetime readonly
Timestamp object was created
modified_at
datetime readonly
Timestamp object was last updated
trigger
string required
Values: bank_account_reject refund void chargeback chargeback_reversal automatic_payment payment decline
url
string required
Url to trigger

Webhook Logs

https://api.payload.co/webhook_logs

Example

{
  "id": "1sytLwaSQUDoYpFc6dWJiCPX4",
  "object": "webhook_log",
  "attrs": {},
  "created_at": "2019-11-22 14:14:08",
  "http_status": 731,
  "modified_at": "2019-11-22 14:14:08",
  "trigger": "bank_account_reject",
  "url": "string",
  "webhook_id": "fAPY1vmYOkUljsHD9cCgeQNk",
  "triggered_on": {
    "id": "If9UPyhhEd6GqhEjtPQg4Hhj",
    "object": "string"
  }
}
Attributes Description
id
string readonly
Object ID
object
string readonly
Value: webhook_log
attrs
json
Custom object attributes
created_at
datetime readonly
Timestamp object was created
http_status
int required
HTTP status reponse from URL
modified_at
datetime readonly
Timestamp object was last updated
trigger
string required
Values: bank_account_reject refund void chargeback chargeback_reversal automatic_payment payment decline
url
string required
Triggered URL
webhook_id
id required
None
triggered_on:  
id
string required
Object ID
object
string required
Object name