API Documentation

Dooplo Developer API

Integrate your application with Dooplo in minutes. This documentation provides ready-to-use code examples in cURL, PHP, Node.js, Java, Ruby and Go to speed up your development.

Base URL

https://api.dooplo.com/v1

Format

JSON request and response bodies

Versioning

Stable /v1 prefix

API guide

How authentication, scopes, limits, pagination and errors work in every endpoint.

Authentication

Create an API key in the Dooplo dashboard (API Keys) and pick its scopes. The client secret is shown only once, right after the key is created: store it safely. Send both on every request in the Authorization header as Bearer CLIENT_KEY:CLIENT_SECRET. A missing, wrong or inactive key answers 401 unauthorized.

curl https://api.dooplo.com/v1/me \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET"
HTTP/1.1 200 OK

{
  "workspace": { "id": "workspaces:12345", "name": "My Store", "logo": null, "created_at": "2026-10-01T00:00:00Z" },
  "scopes": ["items:read", "items:write"],
  "client_key": "ak_4f7e2c90a1b2"
}

Scopes

Each key only reaches what its scopes allow; a key with * has every scope. A request without the required scope answers 403 forbidden, and the message names the missing scope.

Scopes

items:readList and retrieve products and plans.
items:writeCreate, update and delete products and plans.
coupons:readList and retrieve coupons.
coupons:writeCreate, update and delete coupons.
rates:readList and retrieve credit card rates.
rates:writeCreate, update and delete credit card rates.
customers:readList and retrieve customers.
customers:writeCreate, update and delete customers.
charges:readList and retrieve charges.
subscriptions:readList and retrieve subscriptions.
workspaces:readRetrieve the workspace of the key (GET /v1/me).

Rate limit

Requests are limited per API key in windows of one minute. Every authenticated response carries the headers below. Past the limit the API answers 429 rate_limit_exceeded with a Retry-After header: wait that many seconds before trying again.

Headers

X-RateLimit-LimitRequests allowed per minute for the key.
X-RateLimit-RemainingRequests left in the current minute.
X-RateLimit-ResetUnix time (seconds) when the window resets.
Retry-AfterOnly on 429: seconds to wait.

Idempotency

Send an Idempotency-Key header on POST requests to retry safely. The first response is kept for 24 hours per workspace and key: a retry with the same Idempotency-Key gets the same status and body without creating anything again, plus the header Idempotent-Replayed: true. Use a new key (for example a UUID) for each new operation.

curl -X POST https://api.dooplo.com/v1/customers \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET" \
  -H "Idempotency-Key: 6f1c2b8e-4c1d-4f7a-9f0e-2a3b4c5d6e7f" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Maria Silva", "email": "maria@example.com" }'

Pagination

List endpoints return the oldest records first (by creation date, then id). Use limit for the page size and pass the id of the last record as starting_after to get the next page, or the id of the first one as ending_before to get the previous page. has_more tells whether there are more records in that direction and total counts every record that matches the filters. A cursor that does not exist answers 400.

Query parameters

limitinteger1 to 100, default 20. Values out of range are adjusted.
starting_afteridReturns the records after this one.
ending_beforeidReturns the records before this one.
{
  "data": [{ "id": "c8f2k1x9m3", "name": "Maria Silva" }],
  "has_more": true,
  "total": 42
}

Errors

Errors always come as JSON with a code (stable, for your code) and a message (for people). Validation messages name the field.

Status codes

400validation_errorInvalid JSON, missing field, wrong type or value, or a cursor that does not exist.
401unauthorizedMissing, wrong or inactive API key.
403forbiddenThe key does not have the required scope.
404not_foundThe record does not exist, was deleted or belongs to another workspace.
405Method not allowed, for example writing to charges or subscriptions.
409email_taken, code_taken, customer_has_charges, item_in_useConflict with existing data.
423workspace_lockedThe workspace is locked by Dooplo billing: creating items is blocked until it is settled.
429rate_limit_exceededToo many requests; see Retry-After.
500internal_errorUnexpected error on our side. Try again later.
HTTP/1.1 409 Conflict

{
  "code": "email_taken",
  "message": "A customer with this e-mail already exists in this workspace"
}

Values and ids

Money is an integer in cents of the currency (4990 = 49.90). Card rate amounts are in hundredths of a percent (299 = 2.99%). Dates are RFC 3339 in UTC, like 2026-10-23T12:00:00Z. Ids come without a table prefix (c8f2k1x9m3); you can also send them with it (customers:c8f2k1x9m3). An id of another resource answers 404.

Versioning

Every path starts with /v1. Inside v1 we only add things (new endpoints, new fields, new error codes), so ignore fields you do not know. Changes that could break an integration only ship in a new version, like /v2, and v1 keeps working.

Changelog

v12026-10-23Items, Coupons, Rates and Customers (create, retrieve, update, delete and list), Charges and Subscriptions (retrieve and list), with the 11 scopes above.

OpenAPI

The full specification, with every endpoint, schema and scope, is public and needs no key.

https://api.dooplo.com/v1/openapi.json

Checkout (CDN)

Embed the Dooplo checkout on any page with one script and Dooplo.checkout.

Installation

Add the script once on the page and call Dooplo.checkout. It returns a Promise that resolves when the checkout has loaded (onReady already called) and rejects when the element or the saler is missing, the files could not be downloaded, the checkout does not exist, or the API refused the cart of a code checkout. In that last case the error carries the API code and message.

<div id="checkout"></div>

<script src="https://cdn.dooplo.com/checkout/v1/dooplo.js"></script>
<script>
  Dooplo.checkout({ saler: 'SALER_ID', el: '#checkout' })
    .then(function () { console.log('checkout ready'); })
    .catch(function (error) { console.error(error.code, error.message); });
</script>

Checkout kinds and layouts

A link checkout keeps its items, prices and offers in the dashboard. A code checkout only keeps who gets paid (merchants and their methods): the page sends the cart. Prices always come from Dooplo: a price sent by the page is ignored and an order with another amount is refused. All items must share the same currency.

Layouts

defaultForm on the left, order summary in the primary color on the right.
splitHalf screen with the product, half with the form.
stepsForm in three steps with a progress bar.
minimalNarrow column with a collapsible summary.
sheetProduct column on a light tone and the form on a white sheet.
darkDark theme with primary color details.
spotlightSingle centered card over a primary gradient.
classicStore style with numbered sections and a grey sidebar.
embedOne column that takes the width of the host element (from 360px), with no background of its own. Code checkouts always use embed, even if another layout is passed.

Required parameters

salerstringyesCheckout ID in Dooplo.
elstring | ElementyesCSS selector ('#checkout') or the element where the checkout is mounted.
itemsarraycode checkoutCart items: [{ id: 'items:abc', quantity: 2 }]. quantity goes from 1 to 99 (default 1); repeated items have their quantities added. Up to 20 different items.
methodsarraycode checkoutPayment methods to offer: 'pix', 'credit_card', 'boleto'. Only the ones accepted by a merchant of the checkout are shown; unknown values are ignored.

Optional parameters

Invalid values are ignored with a console warning; they never break the checkout. On link checkouts the cart parameters (items, methods, orderBumps, upsells, coupon, installments) are ignored.

orderBumpsarrayItem IDs offered as add-ons in the form (code checkout).
upsellsarrayItem IDs offered after an approved card order (code checkout).
couponbooleantrue shows the coupon field (code checkout). The coupon must be active in the workspace.
installmentsobject{ rate: 'credit_card_rates:ID' }: card installments table (code checkout). It must be active in the workspace.
layoutstringCheckout layout. Overrides the dashboard; code checkouts are always embed.
themeobjectColors, font and sizes (see below).
textsobjectCustom texts (see below). Rendered as text, never as HTML.
localestringLanguage of the default texts: 'pt-BR' (default), 'en' or 'es'.
showobjectBlocks the embed layout adds; without it, embed has only the buyer fields, payment, total and button (see below).
fieldsobjectBuyer fields that can be hidden (see below).
prefillobject{ name, email }: initial values.
paymentobjectOrder and initial payment method (see below).

theme

theme.primaryMain color: buttons, highlights, amounts.
theme.textText color.
theme.backgroundCheckout background color.
theme.fontA Google Fonts family name, loaded automatically. Default: Ubuntu.
theme.secondaryBackground of secondary blocks (embed).
theme.borderBorder color (embed).
theme.errorError message color (embed).
theme.successDiscount and confirmation color (embed).
theme.radiusCorner radius of fields and blocks, like 8px or 0.5rem (embed).
theme.fontSizeBase text size, like 15px (embed).
theme.mode'light' (default) or 'dark' (embed).
theme.varsExtra CSS variables named --letters-digits-and-dashes, with a color or size value.

texts

texts.submitSubmit button.
texts.personalTitleBuyer details title (embed).
texts.paymentTitlePayment title (embed).
texts.nameFull name label.
texts.emailEmail label.
texts.documentDocument label.
texts.phonePhone label.
texts.cardNumberCard number label.
texts.cardExpiryCard expiry label.
texts.cardCvvCard CVV label.
texts.cardHolderCard holder label.
texts.installmentsInstallments label.
texts.couponCoupon label.
texts.couponApplyCoupon apply button.
texts.subtotalSubtotal label.
texts.totalTotal label.
texts.totalTodayTotal due today label (plans).
texts.processingButton text while processing.
texts.secureSecure environment seal.
texts.orderBumpOrder bump title.

show

show.summaryItem list. Default false.
show.itemImageItem photo (the first image of the item); needs summary. Default false.
show.couponCoupon field. Defaults to the coupon parameter: coupon: true already shows it, show.coupon: false hides it.
show.countdownSession countdown bar (15 minutes). Default false (link checkouts follow the dashboard).
show.headerImageHeader image from the dashboard. Default false.
show.sealsSecure environment seal. Default false.

fields

fields.phonefalse hides the phone.
fields.documentfalse hides the document, except for boleto, which requires it.
fields.addressThe address only shows for boleto, which always requires it.

prefill

prefill.nameInitial buyer name.
prefill.emailInitial buyer email.

payment

payment.orderOrder of the payment methods; the ones not listed come after.
payment.initialMethod selected when the checkout opens.

Callbacks and events

An error inside a callback never stops the checkout.

onReadyfunctionCalled when the checkout has loaded: { saler, layout }.
onSuccessfunctionCalled when the order is created, with the API response (order_id).
onErrorfunctionCalled when the checkout cannot open or the order fails: { message, code }.
onEventfunctionCalled as onEvent(name, data) on each step of the flow.

onEvent names

method_change{ method: 'pix' }, when the buyer switches the payment method.
step_change{ step: 'pix' }: pix, boleto or done.
coupon_applied{ code, discount: { type, value } }.
upsell_accepted{ item_id, order_id }.
upsell_declined{ item_id }.

Errors when opening a code checkout

The Promise rejects with an Error that carries code and message; the same message is shown in the checkout.

items_requireditems is missing, empty or not a list.
methods_requiredmethods is missing, empty or not a list.
item_unavailableAn item, bump or upsell does not exist, is inactive, deleted or from another workspace.
item_without_priceAn item has no price.
currency_mismatchThe items are in different currencies.
invalid_quantityA quantity outside 1 to 99 (also after adding repeated items).
too_many_itemsMore than 20 different items.
rate_unavailableThe installments table does not exist, is inactive or from another workspace.
no_payment_methodNone of the methods is accepted by the checkout merchants.

Full example

A code checkout inside a 360px column, with every parameter.

Dooplo.checkout({
  saler: 'SALER_ID',
  el: '#checkout',
  items: [{ id: 'items:ITEM_ID', quantity: 1 }],
  methods: ['pix', 'credit_card'],
  orderBumps: ['items:BUMP_ID'],
  upsells: ['items:UPSELL_ID'],
  coupon: true,
  installments: { rate: 'credit_card_rates:RATE_ID' },
  theme: { primary: '#0f766e', radius: '8px', mode: 'light' },
  texts: { submit: 'Buy now' },
  locale: 'en',
  show: { summary: true, itemImage: true, seals: true },
  fields: { phone: false },
  prefill: { email: 'customer@example.com' },
  payment: { order: ['pix', 'credit_card'], initial: 'pix' },
  onReady: function (info) { console.log('ready', info); },
  onSuccess: function (order) { console.log('order', order.order_id); },
  onError: function (error) { console.warn(error.code, error.message); },
  onEvent: function (name, data) { console.log(name, data); },
}).catch(function (error) {
  console.error(error);
});

Endpoints

Pick a resource on the left to view full request and response examples.

Items

Products and subscription plans. Prices are in cents. Creating items answers 423 while the workspace is locked by Dooplo billing; updating keeps working.

GET/itemsScope items:read

List items

Lists the products and plans of the workspace, oldest first. Filter with `kind` (`product` or `plan`).

Request

curl -X GET https://api.dooplo.com/v1/items?kind=plan&limit=20 \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET"

Response

{
  "data": [
    {
      "id": "i3k9d0s7a2",
      "kind": "plan",
      "name": "Pro",
      "price": 4990,
      "currency_id": "brl",
      "description": "Monthly Pro plan",
      "plan": {
        "period": "monthly",
        "period_value": 1,
        "trial": {
          "value": 7,
          "unit": "day"
        }
      },
      "images": [
        {
          "id": "f1a2b3c4d5",
          "url": "https://cdn.example.com/pro.png"
        }
      ],
      "external_id": "erp-123",
      "metadata": {
        "tier": "pro"
      },
      "active": true,
      "created_at": "2026-10-23T12:00:00Z",
      "updated_at": "2026-10-23T12:00:00Z"
    }
  ],
  "has_more": false,
  "total": 1
}
POST/itemsScope items:write

Create item

`kind`, `name`, `price` and `currency_id` are required, and `plan` too when `kind` is `plan` (`period`: daily, weekly, monthly or yearly; optional `trial` with `unit` day, month or year). Up to 8 `https` image URLs.

Request

curl -X POST https://api.dooplo.com/v1/items \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "kind": "plan",
  "name": "Pro",
  "price": 4990,
  "currency_id": "brl",
  "description": "Monthly Pro plan",
  "plan": {
    "period": "monthly",
    "period_value": 1,
    "trial": {
      "value": 7,
      "unit": "day"
    }
  },
  "images": [
    "https://cdn.example.com/pro.png"
  ],
  "external_id": "erp-123",
  "metadata": {
    "tier": "pro"
  }
}'

Response

HTTP/1.1 201 Created

{
  "id": "i3k9d0s7a2",
  "kind": "plan",
  "name": "Pro",
  "price": 4990,
  "currency_id": "brl",
  "description": "Monthly Pro plan",
  "plan": {
    "period": "monthly",
    "period_value": 1,
    "trial": {
      "value": 7,
      "unit": "day"
    }
  },
  "images": [
    {
      "id": "f1a2b3c4d5",
      "url": "https://cdn.example.com/pro.png"
    }
  ],
  "external_id": "erp-123",
  "metadata": {
    "tier": "pro"
  },
  "active": true,
  "created_at": "2026-10-23T12:00:00Z",
  "updated_at": "2026-10-23T12:00:00Z"
}
GET/items/{id}Scope items:read

Retrieve item

Returns one item of the workspace. An id of another workspace answers 404.

Request

curl -X GET https://api.dooplo.com/v1/items/i3k9d0s7a2 \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET"

Response

{
  "id": "i3k9d0s7a2",
  "kind": "plan",
  "name": "Pro",
  "price": 4990,
  "currency_id": "brl",
  "description": "Monthly Pro plan",
  "plan": {
    "period": "monthly",
    "period_value": 1,
    "trial": {
      "value": 7,
      "unit": "day"
    }
  },
  "images": [
    {
      "id": "f1a2b3c4d5",
      "url": "https://cdn.example.com/pro.png"
    }
  ],
  "external_id": "erp-123",
  "metadata": {
    "tier": "pro"
  },
  "active": true,
  "created_at": "2026-10-23T12:00:00Z",
  "updated_at": "2026-10-23T12:00:00Z"
}
PATCH/items/{id}Scope items:write

Update item

Only the fields you send change; `null` clears an optional field and `{}` changes nothing. Sending `images` replaces all images.

Request

curl -X PATCH https://api.dooplo.com/v1/items/i3k9d0s7a2 \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "price": 5990
}'

Response

{
  "id": "i3k9d0s7a2",
  "kind": "plan",
  "name": "Pro",
  "price": 5990,
  "currency_id": "brl",
  "description": "Monthly Pro plan",
  "plan": {
    "period": "monthly",
    "period_value": 1,
    "trial": {
      "value": 7,
      "unit": "day"
    }
  },
  "images": [
    {
      "id": "f1a2b3c4d5",
      "url": "https://cdn.example.com/pro.png"
    }
  ],
  "external_id": "erp-123",
  "metadata": {
    "tier": "pro"
  },
  "active": true,
  "created_at": "2026-10-23T12:00:00Z",
  "updated_at": "2026-10-23T12:00:00Z"
}
DELETE/items/{id}Scope items:write

Delete item

Deletes the item. Answers 409 `item_in_use` when a checkout uses it (main item, upsell or order bump) or a transaction has it.

Request

curl -X DELETE https://api.dooplo.com/v1/items/i3k9d0s7a2 \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET"

Response

HTTP/1.1 204 No Content

Coupons

Discount coupons. The `code` is what the buyer types in the checkout and is unique among the coupons of the workspace.

GET/couponsScope coupons:read

List coupons

Lists the coupons of the workspace, oldest first.

Request

curl -X GET https://api.dooplo.com/v1/coupons?limit=20 \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET"

Response

{
  "data": [
    {
      "id": "d81kq2m0z7",
      "code": "WELCOME10",
      "name": "Welcome",
      "description": "10% off the first order",
      "kind": [
        "unique"
      ],
      "type": "percent",
      "value": 10,
      "customer_id": null,
      "limit_quantity": null,
      "start_at": null,
      "expire_at": null,
      "active": true,
      "created_at": "2026-10-23T12:00:00Z",
      "updated_at": "2026-10-23T12:00:00Z"
    }
  ],
  "has_more": false,
  "total": 1
}
POST/couponsScope coupons:write

Create coupon

`code` and `value` are required. `type` is `percent` (1 to 100) or `amount` (cents, greater than 0). `kind` has `unique` or `multi`, plus `quantify` (needs `limit_quantity`), `period` (needs `start_at` and `expire_at`) and `customer` (needs `customer_id`). A repeated code answers 409 `code_taken`.

Request

curl -X POST https://api.dooplo.com/v1/coupons \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "code": "WELCOME10",
  "name": "Welcome",
  "description": "10% off the first order",
  "kind": [
    "unique"
  ],
  "type": "percent",
  "value": 10
}'

Response

HTTP/1.1 201 Created

{
  "id": "d81kq2m0z7",
  "code": "WELCOME10",
  "name": "Welcome",
  "description": "10% off the first order",
  "kind": [
    "unique"
  ],
  "type": "percent",
  "value": 10,
  "customer_id": null,
  "limit_quantity": null,
  "start_at": null,
  "expire_at": null,
  "active": true,
  "created_at": "2026-10-23T12:00:00Z",
  "updated_at": "2026-10-23T12:00:00Z"
}
GET/coupons/{id}Scope coupons:read

Retrieve coupon

Returns one coupon of the workspace. An id of another workspace answers 404.

Request

curl -X GET https://api.dooplo.com/v1/coupons/d81kq2m0z7 \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET"

Response

{
  "id": "d81kq2m0z7",
  "code": "WELCOME10",
  "name": "Welcome",
  "description": "10% off the first order",
  "kind": [
    "unique"
  ],
  "type": "percent",
  "value": 10,
  "customer_id": null,
  "limit_quantity": null,
  "start_at": null,
  "expire_at": null,
  "active": true,
  "created_at": "2026-10-23T12:00:00Z",
  "updated_at": "2026-10-23T12:00:00Z"
}
PATCH/coupons/{id}Scope coupons:write

Update coupon

Only the fields you send change; `null` clears an optional field and `{}` changes nothing.

Request

curl -X PATCH https://api.dooplo.com/v1/coupons/d81kq2m0z7 \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "value": 15,
  "active": false
}'

Response

{
  "id": "d81kq2m0z7",
  "code": "WELCOME10",
  "name": "Welcome",
  "description": "10% off the first order",
  "kind": [
    "unique"
  ],
  "type": "percent",
  "value": 15,
  "customer_id": null,
  "limit_quantity": null,
  "start_at": null,
  "expire_at": null,
  "active": false,
  "created_at": "2026-10-23T12:00:00Z",
  "updated_at": "2026-10-23T12:00:00Z"
}
DELETE/coupons/{id}Scope coupons:write

Delete coupon

Deletes the coupon; its code can be used again.

Request

curl -X DELETE https://api.dooplo.com/v1/coupons/d81kq2m0z7 \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET"

Response

HTTP/1.1 204 No Content

Rates

Credit card installment rates. `amount` is the interest in hundredths of a percent (299 = 2.99%) for each number of installments (1 to 12).

GET/ratesScope rates:read

List rates

Lists the card rates of the workspace with their installments, oldest first.

Request

curl -X GET https://api.dooplo.com/v1/rates?limit=20 \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET"

Response

{
  "data": [
    {
      "id": "r5t2n8w1q4",
      "name": "Default installments",
      "active": true,
      "installments": [
        {
          "installments": 2,
          "amount": 199
        },
        {
          "installments": 3,
          "amount": 299
        }
      ],
      "created_at": "2026-10-23T12:00:00Z",
      "updated_at": "2026-10-23T12:00:00Z"
    }
  ],
  "has_more": false,
  "total": 1
}
POST/ratesScope rates:write

Create rate

`name` is required. Installments go from 1 to 12, without repeats, with `amount` of at least 0.

Request

curl -X POST https://api.dooplo.com/v1/rates \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Default installments",
  "installments": [
    {
      "installments": 2,
      "amount": 199
    },
    {
      "installments": 3,
      "amount": 299
    }
  ]
}'

Response

HTTP/1.1 201 Created

{
  "id": "r5t2n8w1q4",
  "name": "Default installments",
  "active": true,
  "installments": [
    {
      "installments": 2,
      "amount": 199
    },
    {
      "installments": 3,
      "amount": 299
    }
  ],
  "created_at": "2026-10-23T12:00:00Z",
  "updated_at": "2026-10-23T12:00:00Z"
}
GET/rates/{id}Scope rates:read

Retrieve rate

Returns one rate of the workspace. An id of another workspace answers 404.

Request

curl -X GET https://api.dooplo.com/v1/rates/r5t2n8w1q4 \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET"

Response

{
  "id": "r5t2n8w1q4",
  "name": "Default installments",
  "active": true,
  "installments": [
    {
      "installments": 2,
      "amount": 199
    },
    {
      "installments": 3,
      "amount": 299
    }
  ],
  "created_at": "2026-10-23T12:00:00Z",
  "updated_at": "2026-10-23T12:00:00Z"
}
PATCH/rates/{id}Scope rates:write

Update rate

Only the fields you send change; `null` clears an optional field and `{}` changes nothing. Sending `installments` replaces all of them.

Request

curl -X PATCH https://api.dooplo.com/v1/rates/r5t2n8w1q4 \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Black Friday installments"
}'

Response

{
  "id": "r5t2n8w1q4",
  "name": "Black Friday installments",
  "active": true,
  "installments": [
    {
      "installments": 2,
      "amount": 199
    },
    {
      "installments": 3,
      "amount": 299
    }
  ],
  "created_at": "2026-10-23T12:00:00Z",
  "updated_at": "2026-10-23T12:00:00Z"
}
DELETE/rates/{id}Scope rates:write

Delete rate

Deletes the card rate.

Request

curl -X DELETE https://api.dooplo.com/v1/rates/r5t2n8w1q4 \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET"

Response

HTTP/1.1 204 No Content

Customers

Customers of the workspace. The e-mail is unique per workspace.

GET/customersScope customers:read

List customers

Lists the customers of the workspace, oldest first.

Request

curl -X GET https://api.dooplo.com/v1/customers?limit=20 \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET"

Response

{
  "data": [
    {
      "id": "c8f2k1x9m3",
      "name": "Maria Silva",
      "email": "maria@example.com",
      "phone": "+5511999990000",
      "metadata": {
        "crm_id": "42"
      },
      "active": true,
      "created_at": "2026-10-23T12:00:00Z",
      "updated_at": "2026-10-23T12:00:00Z"
    }
  ],
  "has_more": false,
  "total": 1
}
POST/customersScope customers:write

Create customer

`name` and `email` are required. An e-mail already used in the workspace answers 409 `email_taken`.

Request

curl -X POST https://api.dooplo.com/v1/customers \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Maria Silva",
  "email": "maria@example.com",
  "phone": "+5511999990000",
  "metadata": {
    "crm_id": "42"
  }
}'

Response

HTTP/1.1 201 Created

{
  "id": "c8f2k1x9m3",
  "name": "Maria Silva",
  "email": "maria@example.com",
  "phone": "+5511999990000",
  "metadata": {
    "crm_id": "42"
  },
  "active": true,
  "created_at": "2026-10-23T12:00:00Z",
  "updated_at": "2026-10-23T12:00:00Z"
}
GET/customers/{id}Scope customers:read

Retrieve customer

Returns one customer of the workspace. An id of another workspace answers 404.

Request

curl -X GET https://api.dooplo.com/v1/customers/c8f2k1x9m3 \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET"

Response

{
  "id": "c8f2k1x9m3",
  "name": "Maria Silva",
  "email": "maria@example.com",
  "phone": "+5511999990000",
  "metadata": {
    "crm_id": "42"
  },
  "active": true,
  "created_at": "2026-10-23T12:00:00Z",
  "updated_at": "2026-10-23T12:00:00Z"
}
PATCH/customers/{id}Scope customers:write

Update customer

Only the fields you send change; `null` clears an optional field and `{}` changes nothing.

Request

curl -X PATCH https://api.dooplo.com/v1/customers/c8f2k1x9m3 \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "phone": null
}'

Response

{
  "id": "c8f2k1x9m3",
  "name": "Maria Silva",
  "email": "maria@example.com",
  "phone": null,
  "metadata": {
    "crm_id": "42"
  },
  "active": true,
  "created_at": "2026-10-23T12:00:00Z",
  "updated_at": "2026-10-23T12:00:00Z"
}
DELETE/customers/{id}Scope customers:write

Delete customer

Deletes the customer. Answers 409 `customer_has_charges` when the customer has charges.

Request

curl -X DELETE https://api.dooplo.com/v1/customers/c8f2k1x9m3 \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET"

Response

HTTP/1.1 204 No Content

Charges

Charges created by the checkout. Read only: POST, PATCH and DELETE answer 405.

GET/chargesScope charges:read

List charges

Lists the charges of the workspace, oldest first. Filters: `status`, `method` (pix, boleto, credit_card), `customer_id`, `created_from` and `created_to` (RFC 3339).

Request

curl -X GET https://api.dooplo.com/v1/charges?status=paid&created_from=2026-10-01T00:00:00Z \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET"

Response

{
  "data": [
    {
      "id": "9f8e7d6c5b4a39281716",
      "customer_id": "c8f2k1x9m3",
      "currency_id": "brl",
      "method": "credit_card",
      "status": "paid",
      "amount": 4990,
      "installments": 1,
      "installments_amount": 4990,
      "external_id": "1234567890",
      "observation": null,
      "items": {
        "lines": [
          {
            "item_id": "i3k9d0s7a2",
            "price": 4990,
            "quantity": 1,
            "total_price": 4990
          }
        ]
      },
      "created_at": "2026-10-23T12:00:00Z",
      "updated_at": "2026-10-23T12:01:00Z"
    }
  ],
  "has_more": false,
  "total": 1
}
GET/charges/{id}Scope charges:read

Retrieve charge

Returns one charge of the workspace.

Request

curl -X GET https://api.dooplo.com/v1/charges/9f8e7d6c5b4a39281716 \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET"

Response

{
  "id": "9f8e7d6c5b4a39281716",
  "customer_id": "c8f2k1x9m3",
  "currency_id": "brl",
  "method": "credit_card",
  "status": "paid",
  "amount": 4990,
  "installments": 1,
  "installments_amount": 4990,
  "external_id": "1234567890",
  "observation": null,
  "items": {
    "lines": [
      {
        "item_id": "i3k9d0s7a2",
        "price": 4990,
        "quantity": 1,
        "total_price": 4990
      }
    ]
  },
  "created_at": "2026-10-23T12:00:00Z",
  "updated_at": "2026-10-23T12:01:00Z"
}

Subscriptions

Subscriptions to plans. Read only: POST, PATCH and DELETE answer 405. `active` tells whether the subscriber has access: `active` and `trialing` are active, and a canceled subscription stays active until `current_period_end`.

GET/subscriptionsScope subscriptions:read

List subscriptions

Lists the subscriptions of the workspace, oldest first. Filters: `customer_id`, `customer_email`, `item_id` (the plan) and `status`.

Request

curl -X GET https://api.dooplo.com/v1/subscriptions?customer_email=maria@example.com&item_id=i3k9d0s7a2 \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET"

Response

{
  "data": [
    {
      "id": "9f8e7d6c5b4a39281716_1",
      "customer_id": "c8f2k1x9m3",
      "currency_id": "brl",
      "status": "active",
      "active": true,
      "amount": 4990,
      "period": "monthly",
      "period_value": 1,
      "current_period_start": "2026-10-23T12:00:00Z",
      "current_period_end": "2026-11-23T12:00:00Z",
      "next_billing_at": "2026-11-23T12:00:00Z",
      "canceled_at": null,
      "paid_at": "2026-10-23T12:01:00Z",
      "items": {
        "charge_key": "9f8e7d6c5b4a39281716",
        "line": {
          "item_id": "i3k9d0s7a2"
        }
      },
      "created_at": "2026-10-23T12:00:00Z",
      "updated_at": "2026-10-23T12:01:00Z"
    }
  ],
  "has_more": false,
  "total": 1
}
GET/subscriptions/{id}Scope subscriptions:read

Retrieve subscription

Returns one subscription of the workspace.

Request

curl -X GET https://api.dooplo.com/v1/subscriptions/9f8e7d6c5b4a39281716_1 \
  -H "Authorization: Bearer CLIENT_KEY:CLIENT_SECRET"

Response

{
  "id": "9f8e7d6c5b4a39281716_1",
  "customer_id": "c8f2k1x9m3",
  "currency_id": "brl",
  "status": "active",
  "active": true,
  "amount": 4990,
  "period": "monthly",
  "period_value": 1,
  "current_period_start": "2026-10-23T12:00:00Z",
  "current_period_end": "2026-11-23T12:00:00Z",
  "next_billing_at": "2026-11-23T12:00:00Z",
  "canceled_at": null,
  "paid_at": "2026-10-23T12:01:00Z",
  "items": {
    "charge_key": "9f8e7d6c5b4a39281716",
    "line": {
      "item_id": "i3k9d0s7a2"
    }
  },
  "created_at": "2026-10-23T12:00:00Z",
  "updated_at": "2026-10-23T12:01:00Z"
}