REST API guide: Authentication, pages, dates, errors and notification verification # Get started > Authenticate with the DPD API and make your first request. The DPD API is a read-only window into your DPD account. Your code can read everything your account holds: storefronts, products, purchases, customers and subscribers. It can also [reactivate a purchase](reference/operations/reactivatepurchase/), which emails the customer their downloads again. Every request goes to this base URL: ```plaintext https://api.getdpd.com/v2 ``` ## Authentication [Section titled “Authentication”](#authentication) The API uses HTTP Basic authentication. The username is your DPD username, and the password is the **API password** on your profile in the DPD admin (it’s different from the password you sign in with). Check that your credentials work by pinging the API with curl: ```bash curl -u YOUR_USERNAME https://api.getdpd.com/v2/ ``` curl asks for the password. Paste your API password and you’ll get: ```json {"status": "SUCCESS"} ``` A wrong username or password gets a `401 Unauthorized`. ## Your first real request [Section titled “Your first real request”](#your-first-real-request) List your storefronts: ```bash curl -u YOUR_USERNAME https://api.getdpd.com/v2/storefronts ``` ```json [ { "id": 1, "name": "My Store", "subdomain": "mystore", "type": "cart", "currency": "USD" } ] ``` (That’s trimmed. Each storefront has a few more fields, listed in [Get a storefront](reference/operations/getstorefront/).) Most other requests take a storefront or product ID from a response like this one. The [endpoint reference](reference/) lists them all. ## Keep the API password secret [Section titled “Keep the API password secret”](#keep-the-api-password-secret) Anyone with your username and API password can read your customers’ names, email addresses and orders. Use it only from your server, never in a web page or an app you hand out, and don’t commit it to a code repository. # Responses, pages and dates > How the DPD API pages through lists, formats dates and money, and reports errors. ## Responses [Section titled “Responses”](#responses) Responses are JSON. A single record (such as a purchase) comes back as an object, and a list comes back as an array of objects. Two endpoints answer in plain text instead: [verify a subscriber](../reference/operations/verifysubscriber/) and [verify a purchase notification](../notifications/). ## Status codes [Section titled “Status codes”](#status-codes) | Code | Meaning | | --------------------------- | -------------------------------------------------------------------- | | `200 OK` | It worked. | | `401 Unauthorized` | The username or API password is wrong. | | `403 Forbidden` | You don’t have access to that record. | | `404 Not Found` | Nothing found. See below. | | `422 Unprocessable Entity` | The request didn’t pass validation. The body has an `errors` object. | | `500 Internal Server Error` | Something went wrong on our side. | | `503 Service Unavailable` | The API is down for maintenance or overloaded. Try again shortly. | A `404` has this body: ```json {"status": "NOTFOUND"} ``` You’ll get it when a record doesn’t exist, but also when a list is empty or you ask for a page past the last one. So a search that matches nothing is a `404`, not an empty array. ## Pages [Section titled “Pages”](#pages) Lists return 100 records a page when you pass `page`: ```bash curl -u YOUR_USERNAME "https://api.getdpd.com/v2/purchases?page=2" ``` Leave `page` off and the API tries to return everything at once, which isn’t guaranteed to work on a big account. To fetch a whole list, start at `page=1` and keep counting up until you get a `404`. ## Dates and times [Section titled “Dates and times”](#dates-and-times) Dates in responses are UNIX timestamps, in seconds. Date filters such as `date_min` and `date_max` accept anything PHP’s [`strtotime()`](https://www.php.net/manual/en/function.strtotime.php) does, like `2024-01-01` or `last monday`. They’re read in your account’s time zone unless the value carries its own, as ISO 8601 (`2004-02-12T15:19:21+00:00`) and RFC 2822 (`Thu, 21 Dec 2000 16:01:07 +0200`) dates do. ## Money [Section titled “Money”](#money) Amounts are strings with two decimal places, like `"19.99"`, so they don’t lose precision on the way through a JSON parser. The currency is on the storefront or purchase. # Verify purchase notifications > Check that a purchase notification POSTed to your site came from DPD. With the URL integration, DPD POSTs the details of each purchase to a URL on your site. Anyone can POST to that URL, so before you act on a notification (say, by creating an account), check that DPD sent it. Send every parameter you received back to the API, unchanged, including `verify_sign`. With curl, that’s one `--data-urlencode` for each parameter (only two are shown here): ```bash curl -u YOUR_USERNAME https://api.getdpd.com/v2/notification/verify \ --data-urlencode "verify_sign=THE_SIGNATURE" \ --data-urlencode "buyer_email=customer@example.com" ``` The answer is plain text, either `VERIFIED` or `INVALID`. In PHP, forwarding the whole POST looks like this: ```php $ch = curl_init('https://api.getdpd.com/v2/notification/verify'); curl_setopt_array($ch, [ CURLOPT_USERPWD => 'YOUR_USERNAME:' . getenv('DPD_API_PASSWORD'), CURLOPT_POSTFIELDS => http_build_query($_POST), CURLOPT_RETURNTRANSFER => true, ]); $verified = curl_exec($ch) === 'VERIFIED'; ```