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');
?>
const tx = await pl.Transaction.get('txn_3bW9JN4CCJFkc9ukQ0umW')
pl.Transaction transaction = await pl.Transaction.GetAsync("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.
    filter_by(
        status: 'processed'
    )
    .all()
<?php
$payments = Payload\Transaction::filter_by(
    array('status'=>'processed', 'type'=>'payment'))->all();
?>
const payments = await pl.select(pl.Payment).filterBy({ status: 'processed' })
pl.Payment payments = await pl.Payment
    .FilterBy(new { status = "processed" })
    .AllAsync();

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="[email protected]" \
    -d name="Matt Perez"
account = pl.Customer.create(
    email='[email protected]',
    name='Matt Perez'
)
account = Payload::Customer.create(
    email: '[email protected]',
    name: 'Matt Perez'
)
<?php
$account = Payload\Customer::create(array(
    'email'=>'[email protected]',
    'name'=>'Matt Perez'
));
?>
const cust = await pl.Customer.create({
    email: '[email protected]',
    name: 'Matt Perez'
})
pl.Customer customer = await pl.Customer.CreateAsync(new
{
    email = "[email protected]",
    name = "Matt Perez"
});

Create Multiple Objects

curl "https://api.payload.co/customers" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -d [0]email="[email protected]" \
    -d [0]name="Matt Perez" \
    -d [0]type="customer" \
    -d [1]email="[email protected]" \
    -d [1]name="Andrea Kearney"
accounts = pl.create([
    pl.Customer(
        email='[email protected]',
        name='Matt Perez'
    ),
    pl.Customer(
        email='[email protected]',
        name='Andrea Kearney'
    )
])
accounts = Payload::create([
    Payload::Customer.new(
        email: '[email protected]',
        name: 'Matt Perez'
    ),
    Payload::Customer.new(
        email: '[email protected]',
        name: 'Andrea Kearney'
    )
])
<?php
$accounts = Payload\Customer::create(array(
    new Payload\Account(array(
        'email'=>'[email protected]',
        'name'=>'Matt Perez'
    )),
    new Payload\Account(array(
        'email'=>'[email protected]',
        'name'=>'Andrea Kearney'
    ))
));
?>
const customers = await pl.create([
    pl.Customer({
        email: '[email protected]',
        name: 'Matt Perez'
    }),
    pl.Customer({
        email: '[email protected]',
        name: 'Andrea Kearney'
    })
])
List<pl.Customer> customers = await pl.CreateAllAsync(
    new pl.Customer(new {
        email="[email protected]",
        name="Matt Perez"
    }),
    new pl.Customer(new {
        email="[email protected]",
        name="Andrea Kearney"
    })
);

Create Request

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

Request Body

{
    "email": "[email protected]",
    "name": "Matt Perez"
}

Create Multiple Objects

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

Request Body

{
    "object": "list",
    "values": [
        {
            "email": "[email protected]",
            "name": "Matt Perez"
        },
        {
            "email": "[email protected]",
            "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="[email protected]"
account.update( email="[email protected]" )
account.update(
    email: '[email protected]'
)
<?php
$account->update(array( 'email'=>'[email protected]' ));
?>
await account.update({ email: "[email protected]" })
await account.UpdateAsync(new { email = "[email protected]" });

Update Objects by Query

curl "https://api.payload.co/customers/[email protected]&mode=query" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -X PUT \
    -d email="[email protected]"
accounts = pl.Customer\
    .filter_by(email='[email protected]')\
    .update(email='[email protected]')
accounts = Payload::Customer.
    filter_by(
        email: '[email protected]'
    ).
    update(
        email: '[email protected]'
    )
<?php
$accounts = Payload\Customer::filter_by(array(
        'email'=>'[email protected]'
    ))->update(array(
        'email'=>'[email protected]'
    ));
?>
const customers = await pl.select(pl.Customer)
    .filterBy({ email: '[email protected]' })
    .update({ email: '[email protected]' })
List<pl.Customer> customers = await pl.Customer
    .FilterBy(new { email = "[email protected]" })
    .UpdateAsync(new { email = "[email protected]" });

Update Multiple Objects

curl "https://api.payload.co/customers/" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -X PUT \
    -d [0][id]="acct_3bW9JMoHcb0u4ZmM7FZ32" \
    -d [0][email]="[email protected]" \
    -d [1][id]="acct_3bW9JMojd17Dm4LSuOxIu" \
    -d [1][email]="[email protected]"
accounts = pl.update([
    [ account1, { 'email': '[email protected]' } ],
    [ account2, { 'email': '[email protected]' } ]
])
accounts = Payload::update([
    [account1, { email: '[email protected]' }],
    [account2, { email: '[email protected]' }]
])
const customers = await pl.update([
    [ account1, { email: '[email protected]' } ],
    [ account2, { email: '[email protected]' } ]
])
List<pl.Customer> customers = await pl.Customer
    .UpdateAllAsync(
        (customer1, new { email = "[email protected]" }),
        (customer2, new { email = "[email protected]" })
    );

Update Request

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

Request Body

{
    "email": "[email protected]"
}

Update Query

PUT https://api.payload.co/customers/[email protected]&mode=query

Request Body

{
    "email": "[email protected]"
}

Update Multiple Objects

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

Request Body

{
    "object": "list",
    "values": [
        {
            "id": "acct_3bW9JN4OEmUpEezSq6TJY",
            "email": "[email protected]"
        },
        {
            "id": "acct_3bW9JN4OmbDd2Kg8bdK4W",
            "email": "[email protected]"
        }
    ]
}


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();
?>
const delAccount = await account.delete()
await account.DeleteAsync();

Delete Objects by Query

curl "https://api.payload.co/customers/[email protected]&mode=query" \
    -u secret_key_3bW9JMZtPVDOfFNzwRdfE: \
    -X DELETE
deleted_accnts = pl.Customer\
    .filter_by(email='[email protected]')\
    .delete()
deleted_accnts = Payload::Customer.
    filter_by(
        email: '[email protected]'
    ).
    delete()
<?php
$deleted_accnts = Payload\Account::filter_by(array(
        'email'=>'[email protected]'
    )).delete();
?>
const delAccounts = await pl.select(pl.Customer)
    .filterBy({ email: '[email protected]' })
    .delete()
var deletedAccounts = await pl.Customer
    .FilterBy(new { email = "[email protected]" })
    .QueryDeleteAsync();

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([
    account1,
    account2
])
const delAccounts = await pl.delete([
    account1,
    account2
])
await pl.DeleteAllAsync(
    account1,
    account2
);

Delete Request

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

Delete Query

DELETE https://api.payload.co/customers/[email protected]&mode=query

Delete Multiple Objects

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

Request Body

{
    "object": "list",
    "values": [
        {
            "id": "acct_3bW9JN4OEmUpEezSq6TJY"
        },
        {
            "id": "acct_3bW9JN4OmbDd2Kg8bdK4W"
        }
    ]
}


Errors

Individual Object

{
    "details": {
        "payment_method_id": "Required"
    },
    "error_description": "payment_method_id",
    "error_type": "InvalidAttributes",
    "object": "error"
}
import payload as pl
from payload.exceptions import InvalidAttributes, NotFound

try:
    cust = pl.Customer.get('your_customer_id')
    pl.Payment.create(customer_id=cust.id, amount=100)
except NotFound as e:
    print("Customer doesn't exist")
except InvalidAttributes as e:
    print(e)
begin
    cust = Payload::Customer.get('your_customer_id')

    Payload::Payment.create(
        amount: 100,
        customer_id: cust.id
    )
rescue Payload::InvalidAttributes => error
    p error.instance_variable_get('@details')
end
<?php
try {
    $payment = Payload\Transaction::create(array(
        'amount'=>100.0,
        'type' => 'payment',
        'customer_id' => 'your_customer_id'
    ));
} catch (Exception $e) {
    var_dump($e->details);
}
?>
try {
    const charge = await pl.Customer.charge({ amount: 100 })
} catch(e) {
    console.log(e.details)
}
try
{
    var cust = await pl.Customer.GetAsync("your_customer_id");
    await cust.ChargeAsync(new { amount = 100 });
}
catch (pl.NotFound e)
{
    Console.WriteLine("Customer doesn't exist");
}
catch (pl.InvalidAttributes e)
{
    Console.WriteLine(e.json());

    foreach (JProperty property in e.details)
        Console.WriteLine($"{property.Name}: {property.Value}");
}

Multiple Objects

{
    "details": {
        "0": {
            "email": "Required"
        },
        "1": {
            "name": "Required"
        }
    },
    "error_description": "[0][email], [1][name]",
    "error_type": "InvalidAttributes",
    "object": "error"
}
import payload as pl
from payload.exceptions import InvalidAttributes

try:
    pl.Customer.create([pl.Customer(name="John Doe"), pl.Customer(email="[email protected]")])
except InvalidAttributes as e:
    print(e)
begin
    Payload::create([
        Payload::Customer.new(
            name: 'John Doe'
        ),
        Payload::Customer.new(
            email: '[email protected]'
        )
    ])
rescue Payload::InvalidAttributes => error
    p error.instance_variable_get('@details')
end
<?php
try {
    $accounts = Payload\Customer::create(array(
        new Payload\Account(array(
            'name'=>'John Doe'
        )),
        new Payload\Account(array(
            'email'=>'[email protected]',
        ))
    ));
} catch (Exception $e) {
    var_dump($e->details);
}
?>
try {
    const customers = await pl.Customer.create([
        { name: 'John Doe' },
        { email: '[email protected]' }
    ])
} catch(e) {
    console.log(e.details)
}
try
{
    var custs = await pl.Customer.CreateAllAsync(
        new pl.Customer(new { name = "John Doe" }),
        new pl.Customer(new { email = "[email protected]" })
    );
}
catch (pl.InvalidAttributes e)
{
    Console.WriteLine(e.json()); // See full error

    // Loop over invalid attributes
    foreach (JProperty item in e.details)
    {
        Console.WriteLine(item.Name + ":");
        foreach (JProperty property in item.Value)
            Console.WriteLine("\t" + 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());
?>
const inv = await pl.Invoice.get('inv_3bW9JNCxdMPBUV510Gf9E')

console.log(inv.json())
var invoice = await pl.Invoice.GetAsync("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
const results = await pl
    .select(
        pl.Invoice.due_date.month(),
        pl.Invoice.due_date.year(),
        pl.Invoice.amount_due.sum()
    )
    .filterBy(
        pl.Invoice.status.eq('overdue'),
        pl.Invoice.due_date.ge(new Date(new Date()-30*3600))
    )
    .groupBy(
        pl.Invoice.due_date.month(),
        pl.Invoice.due_date.year()
    )
// An ARM api request representation
// requesting monthly aging receivables
var results = await pl.Invoice
    .Select(
        pl.Attr.due_date.month(),
        pl.Attr.due_date.year(),
        pl.Attr.amount_due.sum()
    )
    .FilterBy(
        pl.Attr.status.eq("overdue"),
        pl.Attr.due_date.le(DateTime.Now.AddDays(30))
    )
    .GroupBy(new [] {
        pl.Attr.due_date.month(),
        pl.Attr.due_date.year()
    })
    .AllAsync();

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.
    filter_by(amount: '<200').
    all()
<?php
$transactions = Payload\Transactions::filter_by(
    pl::attr()->type->eq('payment'),
    pl::attr()->amount->lt(200)
);
?>
const payments = await pl.Payment.filterBy(pl.Payment.amount.lt(200))
var payments = await 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.
    filter_by(
        amount: ['>100', '<200']
    ).
    all()
<?php
$payments = Payload\Transaction::filter_by(
    pl::attr()->amount->gt(100),
    pl::attr()->amount->lt(200)
));
?>
const payments = await pl.Payment.filterBy(
    pl.Payment.amount.gt(100),
    pl.Payment.amount.lt(200)
)
var payments = await 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').
    all()
<?php
$payments = Payload\Transaction::filter_by(array(
    'risk_flag' => 'denied|in_review'
))->all();
?>
const payments = await pl.select(pl.Payment).filterBy(pl.Payment.risk_flag.eq('denied', 'in_review'))
var payments = await pl.Payment
    .FilterBy(new [] {
        pl.Attr.risk_flag.eq("denied", "in_review")
    })
    .AllAsync();

Like Conditional

payments = pl.Payment.filter_by(
    pl.attr.description.contains('INV -')
).all()
const payments = await pl.select(pl.Payment).filterBy(pl.Payment.description.contains('INV -'))
var payments = await pl.Payment
    .FilterBy(new [] {
        pl.Attr.description.contains("INV -")
    })
    .AllAsync();

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()
const payments = await pl.select(pl.Payments).filterBy(
    pl.Payment.amount.gt(100),
    pl.Payment.amount.lt(200),
    pl.Payment.risk_status.eq('denied', 'in_review'),
    pl.Payment.description.contains('INV -'),
    pl.Payment.created_at.date().ne(new Date(2020,1,1))
)
var payments = await pl.Payments
    .FilterBy(
        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))
    )
    .AllAsync();

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.
    filter_by(
        order_by: 'created_at',
        limit: 10,
        offset: 5
    ).
    all()
<?php
$customers = Payload\Account::filter_by(array(
    'order_by' => 'created_at',
    'limit' => 10,
    'offset' => 5
    ))->all();
?>
const customers = await pl.select(pl.Customer).range(5, 15)
var customers = await pl.Customer
    .OrderBy(new []{
        pl.Attr.created_at.desc(),
        pl.Attr.name.asc(),
        pl.Attr.processing.name
    })
    .Range(5, 15)
    .AllAsync();

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()
const invs = await pl.select(pl.Invoice.due_date, pl.Invoice.amount_due)
var results = await pl.Invoice
    .Select(new []{
        pl.Attr.due_date,
        pl.Attr.amount_due
    })
    .AllAsync();

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"
results = pl.Invoice.select(
    pl.attr.processing, *pl.Invoice ).all()
const invs = await pl.select(pl.Invoice, pl.Invoice.processing)
var results = await pl.Invoice
    .Select(new []{ "*", pl.Attr.processing })
    .AllAsync();

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.defaultParams = { 'fields': ['*', 'conv_fee'] }
pl.Payment.DefaultParams.Fields = new []{ "*", pl.Attr.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"}))
?>
let inv = await pl.Invoice.get('inv_3axWdCgzecx9HR7PSOqP2')
inv = inv.update({
    attrs: {
        'custom': 'data'
    },
})
var inv = await pl.Invoice.GetAsync("inv_3axWdCgzecx9HR7PSOqP2");

await inv.UpdateAsync(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('*', 'lower(email)').
    filter_by(
        'year(created_at)': '2020'
    ).
    all()
<?php
$customers = Payload\Account::select(
        '*', 'lower(email)'
    )->filter_by(array(
        "year(created_at)"=>"2020",
        "fields"=>"*,lower(email)"
    ));
?>
const customers = await pl.select(pl.Customer, pl.Customer.email.lower())
  .filterBy(pl.Customer.created_at.year().eq(2020))
var customers = await pl.Customer
    .Select(new [] { "*", pl.Attr.email.lower() })
    .FilterBy(pl.Attr.created_at.year().eq(2020))
    .AllAsync();

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('sum(amount_due)', 'status').
    filter_by(
        due_date: '>2020-01-01',
        group_by: 'status'
    ).
    all()
<?php
$invoice_stats = Payload\Invoice::select(
        'sum(amount_due)', 'status'
    )->filter_by(
        pl::attr()->due_date->gt("2020-01-01")
    )->group_by('status')
?>
const results = await pl
    .select(pl.Invoice.amount_due.sum(), pl.Invoice.status)
    .filterBy(pl.Invoice.due_date.ge(new Date(2020,1,1)))
    .groupBy(pl.Invoice.status)
var results = await pl.Invoice
    .Select(new []{
        pl.Attr.amount_due.sum(),
        pl.Attr.status
    })
    .FilterBy(pl.Attr.due_date.ge(new DateTime(2020,1,1)))
    .GroupBy(new [] { pl.Attr.status })
    .AllAsync();

foreach (var group in results)
{
    Console.WriteLine($"{} {}")
}
[
  {
    "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