Shell Python Node PHP C# Ruby

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.

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/txn_3bW9JN4CCJFkc9ukQ0umW" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE:
transaction = pl.Transaction.get('txn_3bW9JN4CCJFkc9ukQ0umW')
transaction = Payload::Transaction.get('txn_3bW9JN4CCJFkc9ukQ0umW')
<?php
$transaction = Payload\Transaction::get('txn_3bW9JN4CCJFkc9ukQ0umW');
?>
pl.Transaction.get('txn_3bW9JN4CCJFkc9ukQ0umW')
    .then(function(transaction){})
var transaction = pl.Transaction.get("txn_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\Transaction::filter_by(
    array('status'=>'processed', 'type'=>'payment'))->all();
?>
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/customers/" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -d email="matt.perez@example.com" \
    -d name="Matt Perez"
account = pl.Customer.create(
    email='matt.perez@example.com',
    name='Matt Perez'
)
account = Payload::Customer.create(
    email: 'matt.perez@example.com',
    name: 'Matt Perez'
)
<?php
$account = Payload\Customer::create(array(
    'email'=>'matt.perez@example.com',
    'name'=>'Matt Perez'
));
?>
pl.Customer.create({
    email: 'matt.perez@example.com',
    name: 'Matt Perez'
}).then(function(customer) {});
var customer = pl.Customer.create(new {
    email="matt.perez@example.com",
    name="Matt Perez"
});

Create Multiple Objects

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

Create Request

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

Request Body

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

Create Multiple Objects

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

Request Body

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


Updating Objects

Update individual or multiple objects using the HTTP method PUT.

Update an Individual Object

curl "https://api.payload.co/customers/acct_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/customers/?email=matt.perez@example.com&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::filter_by(array(
        'email'=>'matt.perez@example.com'
    ))->update(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/customers/" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -X PUT \
    -d [0][id]="acct_3bW9JMoHcb0u4ZmM7FZ32" \
    -d [0][email]="matt.perez@newwork.com" \
    -d [1][id]="acct_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' } ]
])
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/customers/{id}

Request Body

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

Update Query

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

Request Body

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

Update Multiple Objects

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

Request Body

{
    "object": "list",
    "values": [
        {
            "id": "acct_3bW9JN4OEmUpEezSq6TJY",
            "email": "matt.perez@newwork.com"
        },
        {
            "id": "acct_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/customers/acct_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/customers/?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\Account::filter_by(array(
        'email'=>'matt.perez@example.com'
    )).delete();
?>
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/customers/" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -X DELETE \
    -d [0][id]="acct_3bW9JN4OEmUpEezSq6TJY" \
    -d [1][id]="acct_3bW9JN4OmbDd2Kg8bdK4W"
deleted_accnts = pl.delete([
    account1,
    account2
])
deleted_accnts = Payload::delete_all([
    account1,
    account2
])
pl.delete_all([
    account1,
    account2
])
pl.delete(new[]{
    account1,
    account2
});

Delete Request

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

Delete Query

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

Delete Multiple Objects

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

Request Body

{
    "object": "list",
    "values": [
        {
            "id": "acct_3bW9JN4OEmUpEezSq6TJY"
        },
        {
            "id": "acct_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/inv_3bW9JNCxdMPBUV510Gf9E" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE:
invoice = pl.Invoice.get('inv_3bW9JNCxdMPBUV510Gf9E')
print(invoice.json())
invoice = Payload::Invoice.get('inv_3bW9JNCxdMPBUV510Gf9E')
puts invoice.json()
<?php
$invoice = Payload\Invoice::get('inv_3bW9JNCxdMPBUV510Gf9E');
echo($invoice->json());
?>
pl.Invoice.get('inv_3bW9JNCxdMPBUV510Gf9E')
    .then(function( invoice ){
        console.log(invoice.json())
    })
var invoice = pl.Invoice.get("inv_3bW9JNCxdMPBUV510Gf9E");
Console.WriteLine( invoice.json() );
{
  "id": "inv_3bW9JNCxdMPBUV510Gf9E",
  "object": "invoice",
  "amount": 1000,
  "description": "INV - 401",
  "due_date": "2020-02-01",
  "type": "membership",
  "items": [{
    "id": "item_3bW9JND5cyoQVPVcCwOkC",
    "object": "line_item",
    "amount": 100,
    "date_incurred": "2020-01-10 20:41:40",
    "description": "Item 1",
    "invoice_id": "inv_3bW9JNCxdMPBUV510Gf9E",
    "type": "item",
    "entry_type": "charge"
  },{
    "id": "item_3bW9JND5l6QlItvoXYUXA",
    "object": "line_item",
    "amount": -100,
    "description": "Payment",
    "invoice_id": "inv_3bW9JNCxdMPBUV510Gf9E",
    "entry_type": "payment",
    "payment": {
      "id": "txn_3bW9JMonPXbEWWcNYrIm0",
      "object": "transaction",
      "account_id": "acct_3bW9JMoMCmrCjZByd1Wt6",
      "amount": 100,
      "processing_id": "acct_3bW9JMoN07ApUDouuPdB2",
      "description": "INV - 401 Payment",
      "fee": 1.95,
      "created_at": "2020-02-20 17:21:15",
      "payment_method": {},
      "payment_method_id": "pm_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/inv_3bW9JNCxdMPBUV510Gf9E/items

Full Object Resource Path

https://api.payload.co/line_items/item_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\Transactions::filter_by(
    pl::attr()->type->eq('payment'),
    pl::attr()->amount->lt(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\Transaction::filter_by(
    pl::attr()->amount->gt(100),
    pl::attr()->amount->lt(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_flag == 'denied') | (pl.attr.risk_flag == 'in_review')
).all()
payments = Payload::Payment.filter_by(
    risk_flag: 'denied|in_review'
)
<?php
$payments = Payload\Transaction::filter_by(array(
    'risk_flag' => 'denied|in_review'
))->all();
?>
pl.Payment.filter_by(
        pl.attr.risk_flag.eq('denied','in_review')
    ).then(function( payments ){
    })
var payments = pl.Payment.filter_by(
    pl.attr.risk_flag.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') | (pl.attr.risk_status == 'in_review'),
    pl.attr.description.contains('INV -'),
    pl.attr.created_at.date() != datetime.date(2020,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(2020,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(2020,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/customers/?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\Account::filter_by(array(
    'order_by' => 'created_at',
    'limit' => 10,
    'offset' => 5
    ))->all();
?>
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/inv_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/inv_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.conv_fee, *pl.Transaction ] }
Payload::Payment.default_params = { fields: ['*'. 'conv_fee' ] }
<?php
Payload\Transaction::default_params = array( 'fields' => ['*', 'conv_fee'] );
?>
pl.Payment.default_params = { 'fields': ['*', 'conv_fee'] }
pl.Payment.default_params = new { attrs=["*", "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/inv_3axWdCgzecx9HR7PSOqP2" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -X PUT \
    -d "attrs[custom]=data"
inv = pl.Invoice.get('inv_3axWdCgzecx9HR7PSOqP2')

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

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

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

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/customers/" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -d "year(created_at)=2020" \
    -d "fields=*,lower(email)"
customers = pl.Customer.select(
        pl.attr.email.lower(),
        *pl.attr
    )\
    .filter_by( pl.attr.created_at.year() == 2020 )\
    .all()
customers = Payload::Customer.select( 'year(created_at)': '2020',
    fields: '*,lower(email)' )
<?php
$customers = Payload\Account::select(
        '*', 'lower(email)'
    )->filter_by(array(
        "year(created_at)"=>"2020",
        "fields"=>"*,lower(email)"
    ));
?>
pl.Customer.select(
        '*', pl.attr.email.lower(),
    ).filter_by(
        pl.attr.created_at.year().eq(2020)
    ).then(function(results) {
    })
var customers = pl.Customer.select(
        "*", pl.attr.email.lower()
    )
    .filter_by( pl.attr.created_at.year().eq( 2020 ) )
    .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=>2020-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(2020,1,1) )\
    .group_by( pl.attr.status )\
    .all()
invoice_stats = Payload::Invoice.select( due_date: '>2020-01-01',
    fields: 'sum(amount_due),status', group_by: 'status' )
<?php
$invoice_stats = Payload\Invoice::select(
        'sum(amount_due)', 'status'
    )->filter_by(
        pl::attr()->due_date->gt("2020-01-01")
    )->group_by('status')
?>
pl.Invoice.select(
        pl.attr.amount_due.sum(),
        pl.attr.status
    ).filter_by(
        pl.attr.due_date.ge(new Date(2020,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(2020,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