NAV Navbar
shell

Introduction

Placements API v1 is a RESTful service and follows JSON api specification. Currently, the API covers:

More functionality will be added over time.

Base Endpoint

https://api.placements.io/v1

Authentication

Example request to retrieve a list of Accounts:

curl 'https://api.placements.io/v1/accounts' \
     -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'

Two authentication mechanisms are supported: Personal Access Token and OAuth2. Either way you will receive an access token (see below for detailed instructions).

To access the Placements API, set the token as a "Bearer Authorization" header in your HTTP request.

Personal Access Token

A user can generate a Personal Access Token to direclty access Placements API. Please keep in mind that any operation by this means is treated exactly like the user operated through UI. Please protect your Personal Access Token just like your normal login credentials.

A logged in user can go to API Access to generate a new token or list / revoke / regenerate existing tokens.

OAuth2

Note: replace YOUR_APPLICATION_ID, YOUR_APPLICATION_SECRET, YOUR_REDIRECT_URL and YOUR_AUTH_CODE with your actual data!

Example request your server sends to exchange auth code into access token:

curl 'https://api.placements.io/oauth/token' \
     -H "Content-Type: application/json" \
     -X POST -d "{\"client_id\":\"YOUR_APPLICATION_ID\",\"client_secret\":\"YOUR_APPLICATION_SECRET\",\"redirect_uri\":\"YOUR_REDIRECT_URL\",\"grant_type\":\"authorization_code\",\"code\":\"YOUR_AUTH_CODE\"}"

You will get back an access token and a refresh token:

{
  "access_token":"YOUR_ACCESS_TOKEN",
  "token_type":"Bearer",
  "expires_in":7200,
  "refresh_token":"YOUR_REFRESH_TOKEN",
  ...
}

Example request to refresh the tokens:

curl 'https://api.placements.io/oauth/token' \
     -H "Content-Type: application/json" \
     -X POST -d "{\"client_id\":\"YOUR_APPLICATION_ID\",\"client_secret\":\"YOUR_APPLICATION_SECRET\",\"grant_type\":\"refresh_token\",\"refresh_token\":\"YOUR_REFRESH_TOKEN\"}"

If it is a 3rd party application that needs to access Placements API on behalf of a user, OAuth2 is more appropriate. Specifically we support OAuth2 Authorization Code Grant for such 3rd party apps.

First, the 3rd party application developer needs to register the app with Placements. For now it is a manual process, please contact us with the following information:

After successful registration, we will give you back:

Your app will need both pieces of information to obtain an OAuth2 Access Token. The flow for getting an OAuth2 Access Token is as follows:

The server at your redirect URL needs to extract the authorization code, then send a POST request to exchange it into an OAuth2 access token. Note that for security purpose, the authorization code will only be valid for 10 minutes.

The access token will be valid for 2 hours, afterwards you will need to refresh with the lastest refresh token to get a new set of access token and refresh token.

As long as the user does not revoke the authorization, your app will continue to be able to obtain new sets of access token and refresh token in such a manner.

Common API Actions

The API supports a common set of actions for all resources. Below we will be using opportunity resource as an example.

List

curl 'https://api.placements.io/v1/opportunities' \
     -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'
{
  "data": [
    {
      "id": "8",
      "type": "opportunities",
      "links": {
        "self": "https://api.placements.io/v1/opportunities/8"
      },
      "attributes": {
        "name": "Test RFP ",
        "close-date": "2015-07-31",
        ...
      },
      "relationships": {
        "advertiser": {
          "links": {
            "self": "https://api.placements.io/v1/opportunities/8/relationships/advertiser",
            "related": "https://api.placements.io/v1/opportunities/8/advertiser"
          },
          "data": {
            "type": "accounts",
            "id": "1912"
          }
        },
      }
    },
    ...
  ],
  "meta": {
    "record-count": 1524,
    "page-count": 153
  },
  "links": {
    "first": "https://api.placements.io/v1/opportunities?page%5Bnumber%5D=1&page%5Bsize%5D=10",
    "next": "https://api.placements.io/v1/opportunities?page%5Bnumber%5D=2&page%5Bsize%5D=10",
    "last": "https://api.placements.io/v1/opportunities?page%5Bnumber%5D=153&page%5Bsize%5D=10"
  }
}

GET resources will return a list of resources. Notice that each resource will have different attributes and relationships. See corresponding section in Resources for specific details.

List with Pagination

For the 2nd page of results, and each page contains 3 entries (notice that [ and ] are URL encoded for curl):

curl 'https://api.placements.io/v1/opportunities?page%5Bnumber%5D=2&page%5Bsize%5D=3' \
     -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'

By default, list returns the first page of results, with each page contains 10 entries. You can derive paging information from the meta and links section. To change how many entries each page contains, use the page[size] parameter (currently the max size allowed is 200). To change which page of results to return, use the page[number] parameter.

List with Select Attributes (aka Sparse Fieldsets)

If you only want "name" and "description" in the results (notice that [ and ] are URL encoded for curl):

curl 'https://api.placements.io/v1/opportunities?fields%5Bopportunities%5D=name,description' \
     -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'

By default, all attributes are returned. It is possible to return only specific attributes with the fields[TYPE] parameter.

List with Filter Results

To filter opportunities (notice that [, ] and are URL encoded for curl):

# id "100" or "101"
curl 'https://api.placements.io/v1/opportunities?filter%5Bid%5D=100,101' \
     -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'

# modified since 2019-01-20 05:04
curl 'https://api.placements.io/v1/opportunities?filter%5Bmodified-since%5D=2019-01-20T05:04Z' \
     -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'

# name "Test 1"
curl 'https://api.placements.io/v1/opportunities?filter%5Bname%5D=Test%201' \
     -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'

It is also possible to filter resources with the filter[] parameter. Currently the following is supported:

Filter Description Param Example
id resources by id filter[id]=100
modified-since resources modified since a given timestamp filter[modified-since]=2019-01-20T05:04Z
name resources by exact name match (only when 'name' is a valid attribute) filter[name]=foo

More filtering capabilities might come later.

Get

curl 'https://api.placements.io/v1/opportunities/1764' \
     -H 'Authorization:bearer YOUR_ACCESS_TOKEN'
{
  "data": {
    "id": "1764",
    "type": "opportunities",
    "links": {
      "self": "https://api.placements.io/v1/opportunities/1764"
    },
    "attributes": {
      "name": "offline recur1ng ",
      ...
    },
    "relationships": {
      "advertiser": {
        "links": {
          "self": "https://api.placements.io/v1/opportunities/1764/relationships/advertiser",
          "related": "https://api.placements.io/v1/opportunities/1764/advertiser"
        },
        "data": {
          "type": "accounts",
          "id": "67793"
        }
      },
      ...
    }
  }
}

GET resources/ID will return one resource.

If you want to include the data of the related "bill-to-account" in the response:

curl 'https://api.placements.io/v1/opportunities/1764?include=bill-to-account' \
     -H 'Authorization:bearer YOUR_ACCESS_TOKEN'
{
  "data": {
    "id": "1764",
    "type": "opportunities",
    "attributes": {
      ...
    },
    "relationships": {
      ...
      "bill-to-account": {
        ...
        "data": {
          "type": "accounts",
          "id": "67793"
        }
      },
      ...
    }
  },
  "included": [
    {
      "id": "67793",
      "type": "accounts",
      ...
      "attributes": {
        ...
      }
    }
  ]
}

By default, the relationship data only contains resource type and id. It is also possible to include the data of the related resources in the response, by specifying the include parameter.

Create

curl 'https://api.placements.io/v1/opportunities' \
     -H 'Authorization:bearer YOUR_ACCESS_TOKEN'  \
     -H 'Content-Type:application/vnd.api+json' \
     -X POST -d '{"data":{"type":"opportunities", "attributes":{"name":"test opp 1", "close-date": "2018-08-07", "stage-name": "Lead"}, "relationships": {"advertiser": {"data": {"type": "accounts","id": "38"}}} }}'
{
  "data": {
    "id": "1767",
    "type": "opportunities",
    "attributes": {
      ...
    },
    "relationships": {
      "advertiser": {
        "data": {
          "type": "accounts",
          "id": "67793"
        }
      },
      ...
    }    
  }
}

POST resources with appropriate payload will create, then return a new resource.

Update

curl 'https://api.placements.io/v1/opportunities/1767' \
     -H 'Authorization:bearer 7428db176c7b3575e70db78da1cadce8ed590bd3' \
     -H 'Content-Type:application/vnd.api+json' \
     -X PATCH -d '{"data":{"id": "1767","type":"opportunities", "attributes":{"budget":"1000"} }}'
{
 "data": {
   "id": "1767",
   "type": "opportunities",
   "attributes": {
     ...
   },
   "relationships": {
     "advertiser": {
       "data": {
         "type": "accounts",
         "id": "67793"
       }
     },
     ...
   }    
 }
}

PATCH resources/ID with appropriate payload will update, then return the resource.

Delete

DELETE resources/ID will delete the resource. Note that we currently do NOT allow deletion yet.

Resources

Accounts

Example account (abbreviated for clarity):

{
  "data": {
    "id": "100268",
    "type": "accounts",
    "links": {
      "self": "https://api.placements.io/v1/accounts/100268"
    },
    "attributes": {
      "name": "The Home Depot",
      ...
      "ad-server-info": [
        {
          "ad-server": "dfp",
          "ad-server-id": 20227938,
          "ad-server-network-code": 88650439
        }
      ],
      ...
    }
  }
}

Base: https://api.placements.io/v1/accounts

Data "type" is "accounts", identified by "id"

Attributes

Name Type Sample Value Notes
name String "account 1" required
description String ""
account-type String (Enum) "ADVERTISER", "AGENCY", "PARTNER" or ""
category String (Enum) "Agriculture", "Apparel", "Banking", "Biotechnology", "Chemicals", "Communications", "Construction", "Consulting", "Education", "Electronics", "Energy", "Engineering", "Entertainment", "Environmental", "Finance", "Food & Beverage", "Government", "Healthcare", "Hospitality", "Insurance", "Machinery", "Manufacturing", "Media", "Not For Profit", "Recreation", "Retail", "Shipping", "Technology", "Telecommunications", "Transportation", "Utilities", "Other"
credit-status String (Enum) "ON_HOLD", "ACTIVE", "CREDIT_STOP", "INACTIVE" or "BLOCKED"
commission Number 0.01
currency-code String "USD"
external-id String ""
street-address1 String ""
street-address2 String ""
city String ""
state String ""
zip String ""
country String ""
time-zone String "Pacific Time (US & Canada)"
website String ""
phone String ""
fax String ""
email String ""
salesforce-id String "00781000000DdL2588"
custom-fields Key value pairs (see Custom Fields section)
ad-server-info Array(Object) (see example) read-only
last-modified DateTime "2018-08-22T22:54:09.023Z"

Relationships

Name Type Notes
contacts Array(Contact)

Campaigns

Example campaign (abbreviated for clarity):

{
  "data": {
    "id": "41",
    "type": "campaigns",
    "links": {
      "self": "https://api.placements.io/v1/campaigns/41"
    },
    "attributes": {
      "name": "Test Campaign 1",
      ...
      "trafficker-info": {
        "email": "[email protected]"
      },
      "sales-planner-info": {
        "email": "[email protected]"
      },
      "primary-salesperson-info": {
        "email": "[email protected]",
        "split-percent": 80
      },
      "secondary-salespeople-info": [
        {
          "email": "[email protected]",
          "split-percent": 20
        }
      ],
      "ad-server-info": [
        {
          "ad-server": "dfp",
          "ad-server-id": 20227938,
          "ad-server-network-code": 88650439
        }
      ],
      ...
    },
    "relationships": {
      "advertiser": {
        "links": {
          "self": "https://api.placements.io/v1/campaigns/41/relationships/advertiser",
          "related": "https://api.placements.io/v1/campaigns/41/advertiser"
        },
        "data": {
          "type": "accounts",
          "id": "3549"
        }
      },
      ...
    }
  }
}

Base: https://api.placements.io/v1/campaigns

Data "type" is "campaigns", identified by "id".

Attributes

Name Type Sample Value Notes
archived Boolean false
name String "campaign 1" required
description String ""
start-date DateTime "2018-08-23T00:00:00.000Z" required
end-date DateTime "2018-08-24T00:00:00.000Z" required
time-zone String "Pacific Time (US & Canada)"
currency-code String "USD" required
budget Number 100.00
po-number String ""
probability Number 75
approval-status String (Enum) "draft", "pending_review", "reviewed", or "partially_reviewed" read-only
delivery-status String "live" read-only
custom-fields Key value pairs (see Custom Fields section)
trafficker-info Object (see example)
sales-planner-info Object (see example)
primary-salesperson-info Object (see example)
secondary-salespeople-info Array(Object) (see example)
ad-server-info Array(Object) (see example) read-only
billing-source String (Enum) "contracted", "first_party_actuals", or "third_party_actuals"
billing-schedule String (Enum) "prepaid", "straightline"
billing-cap String (Enum) "no_cap", "cap_contracted" or "cap_per_billing_cycle"
external-id String ""
last-modified DateTime "2018-08-22T22:54:09.023Z"

Relationships

Name Type Notes
advertiser Account required
agency Account
partner Account
bill-to-account Account
opportunity Opportunity
owner User
line-items Array(Line Item)

Contacts

Example contact (abbreviated for clarity):

{
  "data": {
    "id": "1337",
    "type": "contacts",
    "links": {
      "self": "https://api.placements.io/v1/contacts/1337"
    },
    "attributes": {
      "first-name": "Jon",
      "last-name": "Snow",
      "email": "[email protected]",
      ...
    },
    "relationships": {
      "account": {
        "links": {
          "self": "https://api.placements.io/v1/contacts/1337/relationships/account",
          "related": "https://api.placements.io/v1/contacts/1337/account"
        },
        "data": {
          "type": "accounts",
          "id": "80085"
        }
      }
    }
  }
}

Base: https://api.placements.io/v1/contacts

Data "type" is "contacts", identified by "id".

Attributes

Name Type Sample Value Notes
comments String ""
email String "[email protected]"
external-id String ""
first-name String "Jon" required
last-name String "Snow" required
phone String "555.555.5555"
title String ""
street String ""
street2 String ""
city String "Seattle"
state String "WA"
zip String "98104"
country String "USA"
custom-fields Key value pairs (see Custom Fields section)
last-modified DateTime "2018-04-20T16:20:12.345Z"

Relationships

Name Type Notes
account Account required

Line Items

Example line item (abbreviated for clarity):

{
  "data": {
    "id": "106",
    "type": "line-items",
    "links": {
      "self": "https://api.placements.io/v1/line_items/106"
    },
    "attributes": {
      "name": "Line item 1",
      ...
    },
    "relationships": {
      "campaign": {
        "links": {
          "self": "https://api.placements.io/v1/line_items/106/relationships/campaign",
          "related": "https://api.placements.io/v1/line_items/106/campaign"
        },
        "data": {
          "type": "campaigns",
          "id": "41"
        }
      }
    }
  }
}

// With delivery-stats
{
  "data": {
    "id": "106",
    ...
    "attributes": {
      "delivery-stats": {
        "first-party": {
          "clicks": 724,
          "impressions": 94162670,
          "viewable-impressions": 81683683
        },
        "third-party": {
          "advertiser": "ACME Industries",
          "server": "ImpSlinger",
          "clicks": 956,
          "impressions": 95318149,
          "viewable-impressions": 79151545
        }
      },
      ...
    },
    "relationships": {
      ...
    }
  }
}

Base: https://api.placements.io/v1/line_items

Data "type" is "line-items", identified by "id".

Attributes

Name Type Sample Value Notes
archived Boolean false
name String "line item 1" required
description String ""
ad-server String (Enum) "app_nexus", "dfp", or "offline" required
ad-server-id String ""
ad-server-network-code Number 88650439
approval-status String (Enum) "draft", "pending_review", "approved", or "rejected" read-only
delivery-status String "DELIVERING" read-only
start-date DateTime "2018-08-23T00:00:00.000Z" required
end-date DateTime "2018-08-24T00:00:00.000Z" required
time-zone String "Pacific Time (US & Canada)"
currency-code String "USD" required
cost-basis String (Enum) "CPA", "CPC", "CPD", "CPE", "CPM", "CPU", "CPVM" or "FIXED" required
cost-per-unit Number 0.02 required
contracted-units Number 100
priority Number 14
item-type String "STANDARD" required
goal Number 70
environment-type String (Enum) "BROWSER", "NATIVE", or "VIDEO_PLAYER"
external-id String ""
custom-fields Key value pairs (see Custom Fields section)
delivery-stats Object (see example) (see below)
last-modified DateTime "2018-08-22T22:54:09.023Z"

Relationships

Name Type Notes
campaign Campaign required
product Product read-only
package Package read-only

Opportunities

Example opportunity (abbreviated for clarity):

{
  "data": {
    "id": "52",
    "type": "opportunities",
    "links": {
      "self": "https://api.placements.io/v1/opportunities/52"
    },
    "attributes": {
      "name": "Amazon Fresh Campaign - Fall 2015",
      ...
      "trafficker-info": {
        "email": "[email protected]"
      },
      "sales-planner-info": {
        "email": "[email protected]"
      },
      "primary-salesperson-info": {
        "email": "[email protected]",
        "split-percent": 80
      },
      "secondary-salespeople-info": [
        {
          "email": "[email protected]",
          "split-percent": 20
        }
      ],
      "ad-server-info": [
        {
          "ad-server": "dfp",
          "ad-server-id": 20227938,
          "ad-server-network-code": 88650439
        }
      ],
      ...
    },
    "relationships": {
      "advertiser": {
        "links": {
          "self": "https://api.placements.io/v1/opportunities/52/relationships/advertiser",
          "related": "https://api.placements.io/v1/opportunities/52/advertiser"
        },
        "data": {
          "type": "accounts",
          "id": "3549"
        }
      },
      ...
    }
  }
}

Base: https://api.placements.io/v1/opportunities

Data "type" is "opportunities", identified by "id".

Attributes

Name Type Sample Value Notes
archived Boolean false
name String "opportunity 1" required
description String ""
stage-name String "Closed Won" required
close-date Date "2018-08-07" required
proposal-due-date Date "2018-08-09"
probability Number 5
requirements String ""
time-zone String "Pacific Time (US & Canada)"
currency-code String "USD" required
budget Number 100.00
custom-fields Key value pairs (see Custom Fields section)
trafficker-info Object (see example)
sales-planner-info Object (see example)
primary-salesperson-info Object (see example)
secondary-salespeople-info Array(Object) (see example)
ad-server-info Array(Object) (see example) read-only
last-modified DateTime "2018-08-22T22:54:09.023Z"

Relationships

Name Type Notes
advertiser Account required
agency Account
partner Account
bill-to-account Account
owner User
opportunity-line-items Array(Opportunity Line Item)

Opportunity Line Items

Example opportunity line item (abbreviated for clarity):

{
  "data": {
    "id": "67",
    "type": "opportunity-line-items",
    "links": {
      "self": "https://api.placements.io/v1/opportunity_line_items/67"
    },
    "attributes": {
      "name": "Opportunity Line item 1",
      ...
    },
    "relationships": {
      "opportunity": {
        "links": {
          "self": "https://api.placements.io/v1/opportunity_line_items/67/relationships/opportunity",
          "related": "https://api.placements.io/v1/opportunity_line_items/67/opportunity"
        },
        "data": {
          "type": "opportunities",
          "id": "11"
        }
      }
    }
  }
}

Base: https://api.placements.io/v1/opportunity_line_items

Data "type" is "opportunity-line-items", identified by "id".

Attributes

Name Type Sample Value Notes
archived Boolean false
name String "line item 1" required
description String ""
ad-server String (Enum) "app_nexus", "dfp", or "offline" required
start-date DateTime "2018-08-23T00:00:00.000Z" required
end-date DateTime "2018-08-24T00:00:00.000Z" required
time-zone String "Pacific Time (US & Canada)"
currency-code String "USD" required
cost-basis String (Enum) "CPA", "CPC", "CPD", "CPE", "CPM", "CPU", "CPVM" or "FIXED" required
cost-per-unit Number 0.02
units Number 100
item-type String "STANDARD" required
goal Number 70
environment-type String (Enum) "BROWSER", "NATIVE", or "VIDEO_PLAYER"
custom-fields Key value pairs (see Custom Fields section)
last-modified DateTime "2018-08-22T22:54:09.023Z"

Relationships

Name Type Notes
opportunity Opportunity required

Packages

Example package (abbreviated for clarity):

{
  "data": {
    "id": "2",
    "type": "packages",
    "links": {
      "self": "https://api.placements.io/v1/packages/2"
    },
    "attributes": {
      "name": "test package",
      ...
    }
  }
}

Base: https://api.placements.io/v1/packages

Data "type" is "packages", identified by "id".

Attributes

Name Type Sample Value Notes
active Boolean true
archived Boolean false
name String "line item 1" required
description String ""
custom-fields Key value pairs (see Custom Fields section)
last-modified DateTime "2018-08-22T22:54:09.023Z"

Relationships

Name Type Notes
owner User
products Array(Product)

Products

Example product (abbreviated for clarity):

{
  "data": {
    "id": "2",
    "type": "products",
    "links": {
      "self": "https://api.placements.io/v1/products/2"
    },
    "attributes": {
      "name": "test product",
      ...
    }
  }
}

Base: https://api.placements.io/v1/products

Data "type" is "products", identified by "id".

Attributes

Name Type Sample Value Notes
active Boolean true
archived Boolean false
name String "line item 1" required
description String ""
ad-server String (Enum) "app_nexus", "dfp", or "offline" required
currency-code String "USD" required
cost-basis String (Enum) "CPA", "CPC", "CPD", "CPE", "CPM", "CPU", "CPVM" or "FIXED" required
cost-per-unit Number 0.02
priority Number 14
item-type String "STANDARD" required
goal Number 70
environment-type String (Enum) "BROWSER", "NATIVE", or "VIDEO_PLAYER"
custom-fields Key value pairs (see Custom Fields section)
last-modified DateTime "2018-08-22T22:54:09.023Z"

Relationships

Name Type Notes
owner User

Users

Example user (abbreviated for clarity):

{
  "data": {
    "id": "2",
    "type": "users",
    "links": {
      "self": "https://api.placements.io/v1/users/2"
    },
    "attributes": {
      "active": true,
      ...
    }
  }
}

Base: https://api.placements.io/v1/users

Data "type" is "users", identified by "id".

Attributes

Name Type Sample Value Notes
active Boolean true
city String ""
country String ""
currency-code String "USD"
department String ""
email String "" required
fax String ""
first-name String ""
last-name String ""
mobile String ""
phone String ""
state String ""
street String ""
time-zone String "Pacific Time (US & Canada)"
title String ""
zip String ""
last-modified DateTime "2018-08-22T22:54:09.023Z"

Custom Fields

Assuming that for a resource, two custom fields are setup: "cf1" of type "Text", and "cf2" of type "Number". Below is an example of "custom-fields" value:

"custom-fields": {
   "cf1": "abcd",
   "cf2": "100"
}

For some resources, org admin can setup custom fields to hold arbitrary attributes. A custom field can be of type "Text", "Number" or "Dropdown" (with a pre-defined list of valid values). Please contact your org admin on how to set it up.

Rate Limiting

API requests are rate limited to 60 requests per minute, per user. After the rate limit is exceeded, clients will receive HTTP 429 response ("Too Many Requests") until the rate limit is reset.

Errors

An example error response body:

{
  "errors": [
    {
      "title": "...",
      "detail": "...",
      ...
      "status": "422"
    }
  ]
}

Sometimes things do not go according to plan and we will return an error response.

In addition, we also return with regular HTTP status code. Below is a partial list:

Error Code Meaning
400 Bad Request -- Your request is invalid.
401 Unauthorized -- Your API access token is missing or wrong.
403 Forbidden -- You don't have the permission for the operation.
404 Not Found -- The specified resource can not be found.
422 Unprocessable Entity -- The request is well-formed but semantically invalid.
429 Too Many Requests -- You're issuing too many requests! Slow down!
500 Internal Server Error -- We had a problem with our server. Try again later or contact support.
503 Service Unavailable -- We're temporarily offline for maintenance. Please try again later.

Support

Please contact our customer support for general questions or requesting permissions.

For detailed technical questions, suggestions, bug reports, etc. Forum might be a better channel.