# NinePay Developers Documentation
> Documentação da API NinePay: cobranças recorrentes e avulsas por cartão, PIX e boleto.
This file holds the full Markdown of every page, in navigation order. Index with links: https://docs.ninepay.com.br/llms.txt
Per-section files: https://docs.ninepay.com.br/docs/llms-full.txt, https://docs.ninepay.com.br/reference/llms-full.txt, https://docs.ninepay.com.br/recipes/llms-full.txt
---
# NinePay Developers
Source: https://docs.ninepay.com.br/
Entenda os fluxos de cobrança, autenticação, sandbox e webhooks, em português e inglês.
Clique aquiTodos os endpoints da API, com parâmetros, respostas, exemplos e Try It para testar no sandbox.
Clique aquiPasso a passo com código pronto: cobrança no PIX e no cartão, assinaturas, webhooks e checkout.
Clique aqui`.
---
# Webhooks
Source: https://docs.ninepay.com.br/docs/webhooks-en
Webhooks notify your system when a customer, a payment or a subscription changes. They, not the checkout return in the browser, are what should grant or suspend access for paying customers.
## Setting up
Register the webhook in the dashboard, under **Integrações → Webhooks**, or through the API (`/v1/automations`):
```bash
curl -X POST https://payments.cefis.com.br/api/v1/automations \
-H "Authorization: Bearer $NINEPAY_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"type": "webhook",
"name": "Meu sistema",
"webhook_url": "https://meusistema.com.br/webhooks/ninepay",
"triggers": ["payment.approved", "payment.updated", "subscription.updated"],
"status": "active"
}'
```
The `webhook_url` must be a public address (`http` or `https`, outside internal networks); otherwise the API responds with 422. Use `https`.
To check the address before waiting for a real event, the webhook form in the dashboard has a test delivery for each event. You can send up to 10 test deliveries per minute; above that, the response is 429 and you just wait a minute. The limit also applies to the test delivery through the API (`POST /v1/automations/test`).
> 📘 A webhook with a secret can only be edited in the dashboard
>
> The API still creates, lists and edits webhooks without a secret, but it responds with 422 in two cases:
>
> - **Webhook managed in Integrações**, such as one that already has a secret (see [Validating](#validating)): it can only be changed in the dashboard, even if it is just the name or the status. The API returns the error in `errors.webhook_url` and the webhook stays as it was.
> - **Event not accepted in `triggers`**: the API returns the error in `errors.triggers.N`, where `N` is the position of the event in the list, starting at 0, and nothing is saved. Use the events from the [Events](#events) table.
>
> ```json
> {
> "message": "Evento inválido.",
> "errors": {
> "triggers.1": ["Evento inválido."]
> }
> }
> ```
## Events
| Event | When |
| --- | --- |
| `customer.created` | A customer was created |
| `customer.updated` | A customer was changed |
| `payment.created` | A charge or invoice was created |
| `payment.updated` | A payment changed (paid, declined, canceled, refunded, settled...) |
| `payment.approved` | A payment was approved |
| `subscription.created` | A subscription was created |
| `subscription.updated` | A subscription changed (activated, overdue, paused, resumed, canceled...) |
| `all` | All of the events above |
## What you receive
A `POST` with `Content-Type: application/json`:
```json
{
"id": 987654,
"type": "payment.approved",
"data": {
"id": 1470491,
"uuid": "6f1c1a52-1d7e-4f43-a7a4-0a5a2b1c9e10",
"status": "paid",
"method": "credit",
"value": 600
},
"created_at": "2026-10-22 14:05:12"
}
```
- `id` identifies the delivery: it is the same on every attempt. Use it to avoid processing the same event twice.
- `type` is the event.
- `data` is the resource in the same format as the API (`GET /customers/{id}`, `GET /payments/{id}` or `GET /subscriptions/{id}`), without the API's `data` envelope.
## Responding
- Respond with a **2xx** status within 10 seconds. Do heavy processing after responding (in a queue, for example).
- Any other status, or no response, counts as a failure, and the delivery is retried: up to 10 attempts, at increasing intervals (1 s, 30 s, 1 min, 5 min, 10 min, 30 min and then every hour).
- Since an event can arrive more than once, and out of order, treat each event as a signal to fetch the resource, not as the final state.
## Validating
Every delivery of a webhook with a secret is signed, so you can be sure it was NinePay that sent it. Two headers come with the `POST`:
| Header | Value |
| --- | --- |
| `X-Ninepay-Timestamp` | The time of the delivery, in seconds (Unix) |
| `X-Ninepay-Signature` | `sha256=` followed by the HMAC-SHA256, in hexadecimal, of `{timestamp}.{body}` |
The HMAC uses the webhook secret (`nep_whs_…`) as the key, and `{body}` is the raw request body, exactly as it arrived, before any JSON parsing. If you re-serialize the JSON, the bytes change and the computation does not match.
To validate:
1. Read the raw body and the two headers.
2. Reject it if the timestamp is more than 5 minutes off from your clock. This prevents someone from replaying a captured delivery.
3. Compute `sha256=` + HMAC-SHA256 of `"{timestamp}.{body}"` with the secret.
4. Compare it with the `X-Ninepay-Signature` header in constant time (do not use `==`). If it does not match, respond with 401.
On each attempt the timestamp is new, so the signature changes from one attempt to the next, even with the same body. Validate each one.
```javascript
// Node.js (Express): the body must arrive raw
// Mount this route before any global app.use(express.json()): otherwise
// req.body arrives already converted to an object and the computation does not
// match. Or apply express.json() only to the other routes and keep express.raw
// only on this one.
const crypto = require('crypto');
app.post('/webhooks/ninepay', express.raw({ type: 'application/json' }), (req, res) => {
const timestamp = req.header('X-Ninepay-Timestamp') || '';
const signature = req.header('X-Ninepay-Signature') || '';
if (!/^\d+$/.test(timestamp) || Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) {
return res.sendStatus(401);
}
const expected = 'sha256=' + crypto
.createHmac('sha256', process.env.NINEPAY_WEBHOOK_SECRET)
.update(`${timestamp}.`)
.update(req.body) // Buffer with the raw body
.digest('hex');
const a = Buffer.from(signature);
const b = Buffer.from(expected);
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
return res.sendStatus(401);
}
const event = JSON.parse(req.body.toString('utf8'));
// queue the processing and respond right away
res.sendStatus(200);
});
```
```php
300) {
http_response_code(401);
exit;
}
$expected = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . $body, getenv('NINEPAY_WEBHOOK_SECRET'));
if (!hash_equals($expected, $signature)) {
http_response_code(401);
exit;
}
$event = json_decode($body, true);
// queue the processing and respond right away
http_response_code(200);
```
### The secret
- The secret is shown only once: when you create the webhook or when you click **Gerar novo segredo**. Copy it and store it somewhere safe, such as an environment variable.
- When you generate a new secret, the previous one stops working immediately. The following deliveries are already signed with the new one, so update your system before generating it, or validate both for a while.
- Webhooks created before signing have no secret and stay unsigned until someone clicks **Gerar segredo**. Without the headers, there is nothing to validate.
> 🚧 The signature does not replace the API lookup
>
> Even with a valid signature, before granting anything, confirm the state in the API with your token: when you receive `payment.approved` for payment `1470491`, call `GET /payments/1470491` and grant access only if the `status` is `paid`.
That way, a forged or replayed `POST` to your address grants nothing.
## Error e-mail
If your address keeps failing, NinePay warns you by e-mail, sent to the e-mail registered on the webhook. The e-mail links straight to that webhook's [logs](#logs). The notice goes out when the webhook accumulates 10 or more consecutive failures and has been failing for 6 hours or more.
- At most 1 e-mail per day per webhook.
- With no e-mail registered, no notice is sent. Webhooks created through the API (`/v1/automations`) have no e-mail: register one in the dashboard, under **Integrações → Webhooks**.
- The webhook is never paused: new events keep going out and start arriving again as soon as your address responds 2xx. An event that exhausted its 10 attempts, however, is not resent. To lose nothing, check in the API what changed while the address was down.
## Logs
To see what NinePay sent and what your server answered, open the dashboard under **Integrações → Logs de Webhooks**. The whole Integrações page is restricted to the account owner: anyone else is redirected.
The list shows your company's webhook deliveries from the last 14 days. Webhook events are stored for 14 days; after that, the logs are deleted. Deleted webhooks keep their logs visible within that window.
Use the filters to find the delivery you are looking for:
- **Evento** (event) and **Webhook**.
- **Status**: **Todos** (all), **Qualquer erro** (any error), or one of the codes 200, 400, 401, 404, 500, 502, 503 and 504.
- **Período** (period): **Hoje** (today), **Últimos 7 dias** (last 7 days), **Últimos 14 dias** (last 14 days), or **Personalizado** (custom), always within the 14 days.
Click a delivery and the **Detalhes do log** (log details) show the URL, the event, the date, the status and code, the duration, the number of attempts, the payload sent and the body of your server's response.
- The screen does not resend events. An event that exhausted its attempts does not go out again; check in the API what changed.
---
# Checkout
Source: https://docs.ninepay.com.br/docs/checkout-en
Take payments on your own page or on a page hosted by NinePay
You can let NinePay collect the payment details in two ways:
The ninepay.js iframe inside your page, matching its look.
Redirect the customer to a NinePay page and get the result by webhook.
In both cases, grant access through the [webhook](/docs/webhooks-en), never through the browser return.
## Which one to choose
- **External checkout:** the quickest integration, with no payment screen to build. The customer leaves your site and pays on a NinePay page.
- **Embedded checkout:** the customer stays on your site. Payment happens in a NinePay iframe inside your page, matching its look.
## Differences
| | External checkout | Embedded checkout (ninepay.js) |
|---|---|---|
| Where the customer pays | On a NinePay page you redirect the customer to | On your page, in a NinePay iframe |
| What stays on your page | No payment screen | Title, amount and the pay button; the iframe shows the methods, the card fields and the PIX QR code |
| Before integrating | Nothing | Register in the dashboard the site addresses that open the iframe (up to five) |
| Subscription | Create plan, customer and subscription, then redirect to `https://checkout.ninepay.com.br/subscription//activate` | Create the subscription with `method` and no card; its first invoice stays open and paying it in the iframe activates the subscription |
| Methods | Those on the NinePay page | Card, PIX Automático, PIX and boleto (no Open Finance: banks don't open inside an iframe) |
| Card data | Stays on the NinePay page | Goes from the iframe straight to NinePay; your page never sees it |
In both cases, the API token stays on your server only.
---
# Embedded Checkout (ninepay.js)
Source: https://docs.ninepay.com.br/docs/embedded-checkout
The embedded checkout puts the payment of a NinePay invoice inside your page. Your page has the title, the amount and **the pay button**; the NinePay iframe has only the payment methods, the card fields and the PIX QR code, styled to match your page.
The card goes from the iframe straight to NinePay: your page never sees it.
## Before you integrate
1. **Register your site address.** In the dashboard (user menu → Integrações → Checkout embutido), register the addresses that will open the checkout: only `https://domain` or `https://domain:port`, without a path, up to five. Without any, the browser refuses the iframe.
2. **Check the plans' methods.** The iframe offers the invoice's `allowed_methods`, in this order: card, PIX Automático, PIX and bank slip. Open Finance does not appear in the embedded checkout, because the bank does not open in an iframe. Subscription invoices inherit the plan's methods.
## On your server
Everything that uses the API token stays on your server. **The token never goes to the browser.**
### A one-off charge
Create the open invoice, without a card, with `open: true` and the methods the iframe may offer:
```bash
curl -X POST https://payments.cefis.com.br/api/v1/payments \
-H "Authorization: Bearer $NINEPAY_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"customer": { "id": 123 },
"method": "credit",
"open": true,
"allowed_methods": ["credit", "pix", "billet"],
"value": 5000,
"due_date": "2026-11-10"
}'
```
`allowed_methods` is required with `open`. Nothing is charged on creation: the invoice waits for payment in the iframe. Send the `payment.uuid` from the response to the page.
### A subscription
Create the subscription with the `method` and **without a card**. It starts as `new`, with the first invoice open; that invoice is the one that goes to the iframe, and paying it activates the subscription.
```bash
curl -X POST https://payments.cefis.com.br/api/v1/subscriptions \
-H "Authorization: Bearer $NINEPAY_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"customer": { "id": 123 },
"plan": { "id": 456 },
"method": "credit",
"allowed_methods": ["credit"]
}'
```
- The response contains `customer`, `subscription` and `payment`: send the `payment.uuid` to the page.
- **Without the `method`, the subscription is created without any invoice**, and there is nothing to pay in the iframe.
- `allowed_methods` is optional: a subset of the plan's methods, for the first invoice only (later ones use the plan's). With `["credit"]`, the iframe shows only the card.
### After the payment
- **Grant or suspend access only through the webhook**, confirming with `GET /payments/{id}`. The `paid` event on the page is for updating the screen: a browser event can be forged.
- A `new` subscription that is not paid **is not canceled automatically**. Cancel the subscription with `POST /subscription/cancel` and the body `{ "subscription": { "id": 789 } }`, and the open invoice with `DELETE /payments/{id}`.
- A canceled invoice can no longer be paid. Cancel the invoices you no longer want.
## On the page
The script always has the same address, `https://checkout.ninepay.com.br/js/v1/ninepay.js`. Fixes and new v1 features reach it without you changing anything; a breaking change gets a new address (`/js/v2/`), and v1 stays online. `Ninepay.version` reports the exact build.
The dashboard's Integrations screen generates this code with the look and options you choose.
```html
```
> 📘 Note
>
> The iframe has no pay button. The button belongs to your page: it calls `elements.submit()` and then `ninepay.confirmPayment({ elements })`.
## Changing the card
The same script, with the subscription uuid and `mode: 'setup'`: only the card fields, and your page's button confirms.
```js
const elements = ninepay.elements({ subscription: '', mode: 'setup' })
elements.create('payment').mount('#cartao')
botao.onclick = async () => {
const { error, subscription } = await ninepay.confirmSetup({ elements })
// subscription.status: 'succeeded' (the new card is now the subscription's card)
}
```
Always use the subscription `uuid`, which comes from your server; never the numeric id.
## Reference
| Call | What it does |
| --- | --- |
| `Ninepay(options?)` | Creates the client. `options.origin` only for another environment (sandbox); without it, the origin the script was loaded from applies |
| `Ninepay.version` | The exact build, `1.` |
| `ninepay.elements({ payment, appearance? })` | The group for a payment. To change the card: `{ subscription, mode: 'setup', appearance? }` |
| `elements.create('payment', options?)` | The element. Options: `layout`, `paymentMethods`, `paymentMethodOrder`, `texts`, `saveCard`, `title` |
| `elements.update({ appearance })` | Changes the look; the mounted element follows |
| `elements.submit()` | Validates and shows errors in the iframe, without sending: `{ selectedPaymentMethod }` or `{ error }` |
| `element.mount(target)`, `unmount()`, `destroy()` | Adds and removes the iframe; after `destroy`, it can no longer be mounted |
| `element.update(options)` | Changes the element's options (does not change the invoice, the subscription or the mode) |
| `element.focus()`, `blur()` | Focus on the first empty field, or out of the iframe |
| `element.clear()` | Clears the card fields; the chosen method stays |
| `element.collapse()` | Goes back to choosing the method (`accordion` and `steps` layouts) |
| `element.on/once/off(event, fn)` | The events below; an unknown name throws an error |
| `ninepay.confirmPayment({ elements })` | Pays: `{ payment: { id, status, method } }` or `{ error }`. Always resolves |
| `ninepay.confirmSetup({ elements })` | Changes the card: `{ subscription: { id, status } }` or `{ error }` |
### Element options
| Option | Values | What it does |
| --- | --- | --- |
| `layout` | `'tabs'` (default), `'accordion'`, `{ type: 'accordion', defaultCollapsed?, radios?: 'always' \| 'never', spacedAccordionItems? }` or `'steps'` | How the person chooses the method: tabs, a list that expands the chosen method, or a choice screen with "Trocar forma de pagamento" (change payment method) |
| `paymentMethods` | list of methods | Only these methods appear, always within those the invoice accepts. Empty or missing, all of the invoice's methods |
| `paymentMethodOrder` | list of methods | Only reorders the remaining methods |
| `texts` | `'card.holder'`, `'card.number'`, `'card.expiry'`, `'card.cvc'` | Change the card field labels (text, up to 40 characters) |
| `saveCard` | `'ask'` (default), `'always'` or `'never'` | The "Cobrar automaticamente os próximos pagamentos neste cartão" (charge future payments to this card automatically) checkbox, on subscription invoices. `'always'` only applies when the subscription is already on card; the subscription's method never changes without the person agreeing |
| `title` | text | The iframe title, for screen readers |
The methods are `credit`, `pix_automatic`, `pix` and `billet`. For example, on a one-off installment of a subscription with PIX Automático, `paymentMethods: ['credit', 'pix', 'billet']` hides PIX Automático.
### Events
All of them come with `elementType: 'payment'`.
| Event | Data | When |
| --- | --- | --- |
| `loaderstart` | — | Right after `mount` |
| `ready` | `status`, `payable`, `methods` | Once per `mount`. `payable` is false when the invoice is paid, canceled or refunded, or has no available method |
| `change` | `empty`, `complete`, `collapsed`, `value: { type }` | The person chooses or switches the method, or the fields become complete or empty |
| `focus`, `blur` | — | Focus enters or leaves the iframe (also when switching browser tabs) |
| `escape` | — | The person pressed Esc inside the iframe |
| `copy` | `value: { type }` | The person copied the PIX code or the bank slip line (the code is not included). When you listen to `copy`, the "Código copiado!" notice is up to your page |
| `paid` | — | The payment made on this screen, including PIX or bank slip paid later |
| `loaderror` | `error` | The payment did not load, or the iframe did not open within 15 s (check the site address in the dashboard) |
| `resize` | `height` | The content height changed |
### Errors
Errors come as `{ type, code, message }`, with `message` in Portuguese, ready to display:
| `type` | `code` |
| --- | --- |
| `validation_error` | `incomplete`, `no_method` |
| `card_error` | `card_declined` |
| `invalid_request_error` | `not_ready`, `not_payable`, `in_progress`, `not_mounted`, `destroyed`, `wrong_mode` |
| `rate_limit_error` | `rate_limited` |
| `api_error` | `api_error`, `unexpected` |
| `api_connection_error` | `timeout` (no response within 65 s on `confirm` or 15 s on `submit`), `load_timeout` (the iframe did not open) |
## Appearance
`appearance` accepts `{ theme?, labels?, inputs?, variables?, rules? }`. Anything that does not follow the format is ignored, without an error, and the default applies.
- `theme`: `'default'` (neutral), `'night'` or `'flat'`, the starting point for the variables.
- `labels`: `'auto'` (default), `'above'` (the label above the field) or `'floating'` (inside the field, moving up as you type).
- `inputs`: `'spaced'` (default) or `'condensed'` (the card fields in a single block).
**The company's default appearance.** In Integrações → Checkout embutido, in the dashboard, you save a theme and the variables; the iframe uses this appearance when the page does not send `appearance`. What the page sends wins, variable by variable; a `theme` different from the saved one discards the saved variables. A change in the dashboard shows up within a minute.
### Variables
| Variable | Format | Where it applies |
| --- | --- | --- |
| `colorPrimary` | `#rgb` or `#rrggbb` | The buttons (methods, copy code) |
| `colorOnPrimary` | `#rgb` or `#rrggbb` | The button text |
| `colorText` | `#rgb` or `#rrggbb` | The text and the base of the field borders |
| `colorTextSecondary` | `#rgb` or `#rrggbb` | Supporting text |
| `colorTextPlaceholder` | `#rgb` or `#rrggbb` | The placeholder text inside the fields |
| `colorBackground` | `#rgb` or `#rrggbb` | The background of the iframe and the fields |
| `colorBorder` | `#rgb` or `#rrggbb` | The field borders |
| `colorDanger` | `#rgb` or `#rrggbb` | Field errors |
| `fontFamily` | comma-separated font names, up to 120 characters | All text. System fonts or `Inter`, which the checkout serves (external fonts cannot be loaded) |
| `fontSizeBase` | number, 12 to 20 (px) | The text size. Below 16, phones zoom in when a field gets focus |
| `borderRadius` | number, 0 to 24 (px) | The corners of fields and buttons |
| `spacingUnit` | number, 1 to 8 (px) | The padding inside the fields (default 2) |
> 🚧 Contrast
>
> Contrast of the variables is the integrator's responsibility. For the fields to be legible and accessible, use text and background with at least 4.5:1, and border and background with 3:1 (WCAG 1.4.3 and 1.4.11).
### Rules
`rules` applies CSS by public class: `{ ".Tab--selected": { "borderColor": "#47a472" } }`. Each selector is a class, with at most one state and one pseudo-class, in that order (`.Class--state:pseudo`).
| Class | States | Pseudo-classes | Where |
| --- | --- | --- | --- |
| `.Tab`, `.TabIcon`, `.TabLabel` | `--selected` | `:hover` `:focus` `:active` `:disabled` | The method tabs (`tabs` layout) |
| `.AccordionItem` | `--selected` | `:hover` `:focus-visible` | Each method in the `accordion` layout |
| `.RadioIcon` | `--checked` | — | The radio of each `accordion` method |
| `.StepOption` | — | `:hover` `:focus-visible` | Each method in the `steps` layout choice |
| `.StepHint` | — | — | The sentence under each method in `steps` |
| `.StepBack` | — | `:hover` `:focus-visible` | The "Trocar forma de pagamento" (change payment method) link in `steps` |
| `.Label` | `--empty` `--invalid` `--focused` `--floating` `--resting` | — | The label of each card field |
| `.Input` | `--empty` `--invalid` `--complete` | `:hover` `:focus` `:disabled` `:autofill` `::placeholder` `::selection` | The card fields |
| `.Error` | — | — | Each field's error and the card decline |
| `.Block` | — | — | The box with the PIX code and the bank slip line |
| `.Text` | — | — | The PIX, PIX Automático and bank slip texts |
| `.CopyButton` | — | `:hover` `:focus-visible` | The copy buttons |
| `.Link` | — | `:hover` `:focus-visible` | The "Acessar boleto" (open bank slip) link |
| Property | Format |
| --- | --- |
| `color` | A color (as below) with alpha of 0.5 or higher |
| `backgroundColor`, `borderColor` | `#rgb`, `#rrggbb`, `#rrggbbaa`, `rgb()`/`rgba()` or `transparent` |
| `borderWidth` | Up to 4 lengths from 0 to 4px |
| `borderStyle` | `solid`, `dashed` or `none` |
| `borderRadius` | Up to 4 lengths from 0 to 999px |
| `boxShadow` | `none`, or up to two shadows with offsets up to 24px, blur up to 24px and spread up to 4px |
| `padding` | Up to 4 lengths from 0 to 32px |
| `fontFamily` | Same as the variable |
| `fontSize` | From 10 to 24px |
| `fontWeight` | `normal`, `bold` or from `300` to `800` |
| `letterSpacing` | From -2 to 4px |
| `lineHeight` | From `1` to `2` unitless, or from 12 to 36px |
| `textTransform` | `none`, `uppercase`, `lowercase` or `capitalize` |
| `transition` | Up to 4 of `color`, `background-color`, `border-color` or `box-shadow`, with the duration in ms |
A length is `0` or a number in `px`, `rem` or `em` (`rem` and `em` count as 16px). Not accepted: `url()`, `var()`, `!important`, attribute, descendant or sibling selectors, or properties that change the layout (`position`, `display`, `width`, `height`, `margin`, `transform` and similar). Limits: 40 selectors, 12 properties per selector and 120 characters per value. A rule with `color` or `backgroundColor` contrast below 3:1 is discarded. In older browsers (before Safari 16.4), rules do not apply and only the variables are used.
## Precautions
- Always load the script from `https://checkout.ninepay.com.br`, never from a copy or a CDN: the iframe's origin is the one the script came from. For the sandbox, pass `Ninepay({ origin: 'https://...' })`; only `https` is accepted (or `http://localhost`, for testing).
- The page's CSP must allow the checkout: `script-src` and `frame-src` with `https://checkout.ninepay.com.br`.
- Display any data that comes from the iframe as text, never in `innerHTML`.
- The script does not use SRI, because it receives fixes at the same address. If you need SRI, ask NinePay for a frozen copy.
- Do not mount the checkout inside another iframe. If your page puts `sandbox` on a surrounding iframe, include `allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox` (the bank slip PDF opens in another tab).
- The iframe limits confirmations (one at a time and five per minute), but protection against card testing is NinePay's, on the server.
---
# External Checkout
Source: https://docs.ninepay.com.br/docs/external-checkout
The external checkout lets you process payments, links and subscriptions without building a checkout on your website or app.
## How it works
The flow is very simple: you send the customer to a NinePay page where they make the payment and/or subscribe, and NinePay notifies your system via webhook!
## Example: creating a subscription with predefined customer data
When creating a subscription, NinePay needs to collect basic customer information such as name and email. Sometimes you will prefer your own system to send this information instead of letting the customer fill it in at checkout, since they may make mistakes along the way.
For that, we recommend that, before sending the customer to the external checkout, your system makes a call to create this customer's record in NinePay. Then, with their ID in your system, you can use the Create a Subscription resource already linked directly to this customer, and they will only need to fill in the payment details at checkout.
> 👍 Tip
>
> Another advantage of this flow is that, with the customer ID saved in your system beforehand, you can receive and process notifications/webhooks more easily.
## Using the endpoints to create a subscription with predefined customer data
1. Use the [create plan endpoint](/reference/criar-novo-plano) or create one in the dashboard. You need a plan to create a subscription, because every subscription is linked to a plan.
2. Use the [create customer endpoint](/reference/criar-novo-cliente). Every subscription has a linked customer.
3. Use the [create subscription endpoint](/reference/criar-nova-assinatura). In this endpoint's success response, you will receive a `uuid` field in the subscription data. Use this value to redirect the user to the checkout page:
- in production: `https://checkout.ninepay.com.br/subscription//activate`;
- in the sandbox: `https://app.sandbox.cefispay.com.br/subscription//activate`.
> 📘 Note
>
> Replace `` with the value received when creating the subscription.
---
# Criar novo pagamento
Source: https://docs.ninepay.com.br/reference/criar-novo-pagamento
Realiza uma cobrança via cartão de crédito, boleto bancário ou PIX. **Nota:** Pagamentos com cartão devem incluir um hash de cartão (se você ainda não sabe como obter um, consulte a sessão [Hash de cartões](/referencia/ninepay-api#encriptando-os-dados-do-cartão)) ou os dados do cartão. Dê sempre preferência ao método de hash por ser uma alternativa mais segura.
**Cartão de crédito:** o cliente do pagamento (informado em `customer` ou já cadastrado) precisa ter CPF ou CNPJ, telefone, CEP e número do endereço. Esses dados são enviados à adquirente como dados do titular, e a cobrança é recusada se algum deles estiver faltando. Recomendamos cadastrar o cliente com o máximo de informações possível, mesmo que hoje você só cobre por boleto ou Pix.
# OpenAPI definition
```json
{
"openapi": "3.0.3",
"info": {
"title": "NinePay API",
"version": "1.0",
"x-logo": {
"url": ""
},
"termsOfService": "https://bit.ly/cefispay-contrato",
"contact": {
"name": "NinePay Engineering Team",
"email": "ti@ninepay.com.br"
},
"description": "# Introdução\nBem vindo a referência da **API NinePay**.\nÉ através desta API que você integra o seu sistema ao nosso.\nNossa API é RESTful, e todas suas respostas são em JSON, no endpoint base:\n```\nhttps://payments.cefis.com.br/api/v1/\n```\n\n## Ambientes\nAlém do ambiente de **produção** temos disponível o ambiente **sandbox**\npara a realização de testes de integração. Toda a comunicação com o ambiente sandbox deve ser feita através da url:\n\n```\nhttps://api.sandbox.cefispay.com.br/api/v1/\n```\n\n## Autenticação\nTodas as requisições que requerem autenticação, deverão informar no header `Authorization` o token de api enviado pela nossa equipe, observando sempre o ambiente desejado e no seguinte formato:\n```\nAuthorization: Bearer \n```\n\n## Headers\nRecomendamos que os cabeçalhos da requisições sejam corretamente adicionados para trabalhar com os tipos de dados enviados e recebidos da API:\n - Todas as requisições devem contem o header `Content-Type: application/json`, a menos que o endpoint específico defina diferente\n - Todas as requisições devem contem o header `Accept: application/json`, a menos que o endpoint específico defina diferente\n\n## Respostas\n- Os recursos vêm dentro de `data`: `GET /customers/{id}` responde `{ \"data\": { ... } }`.\n- As criações respondem **201**. `POST /payments` responde `{ \"customer\", \"payment\", \"invoice_url\" }` (o `invoice_url` só no boleto) e `POST /subscriptions` responde `{ \"customer\", \"subscription\" }`.\n- Valores sempre em centavos (inteiro): R$ 50,00 é `5000`.\n\n## Erros\nTodo erro tem o mesmo formato:\n```json\n{\n \"code\": \"VALIDATION_ERROR\",\n \"message\": \"Os dados informados são inválidos.\",\n \"errors\": { \"email\": [\"O campo email é obrigatório.\"] },\n \"timestamp\": \"2026-10-22T12:03:54+00:00\",\n \"request_id\": \"64d62d36-e797-45ed-a9d5-c203bde81032\",\n \"documentation_url\": \"https://docs.ninepay.com.br\",\n \"suggestion\": \"Corrija os campos e tente novamente.\"\n}\n```\n`errors` só vem na validação, com uma **lista** de mensagens por campo. `suggestion` vem quando há uma. Guarde o `request_id` para falar com o suporte.\n\n| `code` | HTTP | Quando |\n| --- | --- | --- |\n| `AUTHENTICATION_ERROR` | 401 | Token ausente ou inválido |\n| `FORBIDDEN_ERROR` | 403 | O recurso não é da sua empresa. Em várias rotas, um id que não existe também responde 403, para não revelar quais ids existem |\n| `COMPANYBLOCKED_ERROR` | 403 | A conta está suspensa |\n| `RESOURCE_NOT_FOUND_ERROR` | 404 | O recurso não existe |\n| `ROUTE_NOT_FOUND_ERROR` | 404 | A rota não existe |\n| `METHOD_NOT_ALLOWED_ERROR` | 405 | O método não vale para a rota (ex.: `PUT /customers` sem o id) |\n| `INVALID_STATE_ERROR` | 400 | O recurso não está num estado que permita a ação (ex.: cancelar um pagamento já pago) |\n| `VALIDATION_ERROR` | 422 | Dados inválidos; veja `errors` |\n| `REFUND_NOT_ALLOWED` | 422 | O pagamento não pode ser reembolsado |\n| `TOO_MANY_ATTEMPTS` | 429 | Muitas requisições; respeite o cabeçalho `Retry-After` |\n| `UNEXPECTED_ERROR` | 500 | Erro nosso; se repetir, fale com o suporte com o `request_id` |\n\n## Paginação\nAs listagens recebem `page` (a partir de 1) e `limit` (itens por página: **10** por padrão, de 1 a **100**). A resposta traz `data` (os itens), `links` e `meta` (`current_page`, `last_page`, `per_page`, `total`).\n\n## Datas\n- Datas de calendário (`due_date`, `next_payment`) vão como `AAAA-MM-DD` na requisição.\n- Nas respostas, os campos de data e hora aparecem em dois formatos: ISO 8601 em UTC (`2026-10-27T03:00:00.000000Z`, em `due_date` e `ref_date` do pagamento) e `AAAA-MM-DD HH:MM:SS` no horário de Brasília (`created_at` e `updated_at`). Leia o campo pelo formato dele.\n\n## Identificadores\nCada recurso tem um `id` numérico e um `uuid`. Use o `id` nas rotas autenticadas e o **`uuid`** em tudo que é público (o link de pagamento, o checkout e o PDF do boleto).\n\n# Hash de cartões\nO hash de um cartão é uma versão criptografada de todos os dados do cartão do cliente, essa é a maneira mais segura de enviar os dados do cartão\ndo seu cliente diretamente para a gente. Abaixo vamos detalhar como ele funciona e como obter um hash a partir dos dados inseridos pelo cliente.\nÉ importante ressaltar que esse fluxo deve ser executado no front-end, seja ele web ou mobile, e que os dados do cartão do cliente nunca devem\nser enviados para o backend, já o hash do cartão pode ser enviado para o backend sem problemas.\n\n## Gerando uma encryption key\nA encryption key consiste basicamente em uma chave pública RSA usada para encriptar os dados do cartão, essa chave só pode ser usada uma vez, então\nsempre que precisar encriptar um novo cartão você precisa gerar uma nova encryption key.\n\nPara gerar uma encryption key é necessário fazer uma requisição ``POST`` para a rota ``/encryption_keys`` da API enviando como parâmetro seu\n``merchant_id``. Ela não usa o token da API (nunca o coloque no front-end): o ``merchant_id`` identifica a sua conta, e um\n``merchant_id`` que não existe responde 401.\n\nA requisição deverá ter esse formato:\n```\ncurl -X POST https://payments.cefis.com.br/api/v1/encryption_keys -H 'Content-Type: application/json' -d '{\"merchant_id\":\"SEU_MERCHANT_ID\"}'\n```\n\nComo resposta você receberá um objeto JSON no seguinte formato:\n```\n{\n \"id\": 1111,\n \"public_key\": \"-----BEGIN PUBLIC KEY-----\\n ... \\n-----END PUBLIC KEY-----\\n\",\n \"ip_address\": \"000.000.000.000\",\n \"created_at\": \"2017-07-03\",\n}\n```\n\n## Encriptando os dados do cartão\nPara encriptar os dados do cartão primeiro você precisa formatá-los de forma correta, para isso crie uma string JSON\ncontendo todos os dados do cartão no seguinte formato:\n\n```\n{\"card_number\":\"1111111111111111\",\"card_holder_name\":\"Jose Silva\",\"card_expiration_date\":\"11/2021\",\"card_cvv\":\"111\"}\n```\n\nEm seguida faça a criptografia RSA dessa string utilizando a chave pública (public_key) gerada no passo anterior, com\npadding do tipo PKCS1.\n\nApós criptografar os dados converta a string resultante para base64 e você terá um resultado parecido com esse:\n\n```\nGprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nO último passo é concatenar o id da sua encryption key (recebido como resposta da requisição anterior) com a string\nem base64 que representa os dados do cartão, da seguinte forma:\n\n``encryption_key_id + \"_\" + base64_encrypted_card``\n\nO resultado será o seu card hash:\n\n```\n1111_GprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nPronto, agora os dados do cartão do cliente já estão em um formato seguro para serem transportados pela rede, podendo\nagora ser enviados para o seu back-end dar sequência ao fluxo. Vale lembrar que cada card hash pode ser usado apenas\numa vez e além disso tem uma validade máxima de 30 minutos após a geração da encryption key. Caso seja necessário utilizar\no cartão mais de uma vez faça uma requisição para a rota de cartões e salve esse cartão vinculado ao usuário que o detém,\nassim você receberá um ID único que poderá ser usado para realizar mais transações com o mesmo cartão.\n"
},
"paths": {
"/payments": {
"post": {
"summary": "Criar novo pagamento",
"tags": [
"Pagamentos"
],
"description": "Realiza uma cobrança via cartão de crédito, boleto bancário ou PIX. **Nota:** Pagamentos com cartão devem incluir um hash de cartão (se você ainda não sabe como obter um, consulte a sessão [Hash de cartões](/referencia/ninepay-api#encriptando-os-dados-do-cartão)) ou os dados do cartão. Dê sempre preferência ao método de hash por ser uma alternativa mais segura.\n**Cartão de crédito:** o cliente do pagamento (informado em `customer` ou já cadastrado) precisa ter CPF ou CNPJ, telefone, CEP e número do endereço. Esses dados são enviados à adquirente como dados do titular, e a cobrança é recusada se algum deles estiver faltando. Recomendamos cadastrar o cliente com o máximo de informações possível, mesmo que hoje você só cobre por boleto ou Pix.\n",
"requestBody": {
"$ref": "#/components/requestBodies/PaymentBody"
},
"responses": {
"200": {
"description": "Pagamento criado com sucesso",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaymentStoreResponse"
}
}
}
},
"401": {
"$ref": "#/components/responses/401"
},
"422": {
"$ref": "#/components/responses/422"
},
"500": {
"$ref": "#/components/responses/500"
}
},
"operationId": "createPayment"
}
}
},
"components": {
"securitySchemes": {
"Bearer": {
"type": "apiKey",
"in": "header",
"name": "Authorization",
"description": "Todas as requisições que requerem autenticação devem incluir no cabeçalho `Authorization` o token de API enviado pela nossa equipe. O token deve ser fornecido no seguinte formato:\n```\nAuthorization: Bearer \n```"
}
},
"responses": {
"401": {
"description": "Não autenticado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "AUTHENTICATION_ERROR",
"message": "Não autenticado.",
"timestamp": "2026-10-22T12:03:44+00:00",
"request_id": "f2a7e962-6083-4525-816e-f14d4a602e0a",
"documentation_url": "https://docs.ninepay.com.br"
}
}
}
},
"422": {
"description": "Erro na validação dos dados",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "VALIDATION_ERROR",
"message": "Os dados informados são inválidos.",
"errors": {
"email": [
"O campo email é obrigatório."
]
},
"timestamp": "2026-10-22T12:03:54+00:00",
"request_id": "64d62d36-e797-45ed-a9d5-c203bde81032",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Corrija os campos e tente novamente."
}
}
}
},
"500": {
"description": "Erro inesperado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "UNEXPECTED_ERROR",
"message": "Houve um erro inesperado.",
"timestamp": "2026-10-22T12:04:46+00:00",
"request_id": "868443d3-38fd-4c92-8ea8-7cccbbce4308",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Verifique todos os parâmetros da requisição. Se o erro persistir, entre em contato com nossa equipe em ti@ninepay.com.br."
}
}
}
}
},
"schemas": {
"ApiError": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "O código do erro. Ex.: `VALIDATION_ERROR`, `FORBIDDEN_ERROR`, `UNEXPECTED_ERROR`."
},
"message": {
"type": "string",
"description": "A mensagem do erro."
},
"errors": {
"type": "object",
"description": "Os erros de cada campo, quando o `code` é `VALIDATION_ERROR`.",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "A data e hora do erro, em UTC."
},
"request_id": {
"type": "string",
"description": "Um identificador único gerado para esta resposta de erro."
},
"documentation_url": {
"type": "string",
"description": "O endereço desta documentação."
},
"suggestion": {
"type": "string",
"description": "Uma sugestão de como resolver o erro."
}
}
},
"PaymentStoreResponse": {
"type": "object",
"properties": {
"payment": {
"$ref": "#/components/schemas/Payment"
},
"customer": {
"$ref": "#/components/schemas/Customer"
}
}
},
"Customer": {
"type": "object",
"required": [
"id",
"name",
"email",
"cpf",
"cnpj"
],
"properties": {
"id": {
"description": "O id do cliente na NinePay. Obrigatório se os demais dados do usuário não forem informados",
"type": "integer",
"example": 42,
"readOnly": true
},
"name": {
"description": "O nome do cliente. Obrigatório se o `id` não for informado",
"type": "string",
"example": "Jhon Doe"
},
"email": {
"description": "O email do cliente. Obrigatório se o `id` não for informado",
"type": "string",
"example": "jhon@doe.com"
},
"cpf": {
"description": "O cpf do cliente. Obrigatório se o `id` ou o `cnpj` não forem informados",
"type": "string",
"example": "833.828.600-15"
},
"cnpj": {
"description": "O cnpj do cliente. Obrigatório se o `id` ou o `cpf` não forem informados",
"type": "string",
"example": "95.135.209/0001-79"
},
"phone": {
"description": "O telefone celular do cliente, com DDD. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": "(11) 11111-1111"
},
"cep": {
"description": "O CEP do cliente. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": "01423-910"
},
"address": {
"description": "O endereço do cliente",
"type": "string",
"example": "Rua José Maria Lisboa"
},
"number": {
"description": "O número do endereço do cliente. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": 42
},
"district": {
"description": "O bairro do cliente",
"type": "string",
"example": "Jardim Paulista"
},
"city": {
"description": "A cidade do cliente",
"type": "string",
"example": "São Paulo"
},
"state": {
"description": "O estado do cliente",
"type": "string",
"example": "SP"
},
"country": {
"description": "O código do país do cliente, no formato Alpha 2 de acordo com a [ISO 3166](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes).",
"type": "string",
"example": "BR"
}
}
},
"Payment": {
"type": "object",
"properties": {
"id": {
"description": "The payment id",
"type": "integer",
"example": 42
},
"uuid": {
"description": "Public payment id",
"type": "string",
"format": "uuid",
"example": "8b2cad02-06f0-42be-84ac-101b23a1bb0d"
},
"value": {
"description": "Payment value in cents",
"type": "integer",
"minLength": 1,
"example": 5000
},
"due_date": {
"description": "Payment due date",
"type": "string",
"format": "date",
"example": "2017-07-21"
}
}
},
"PaymentBody": {
"type": "object",
"required": [
"method",
"customer"
],
"properties": {
"method": {
"description": "O método que será usado para este pagamento. Posteriormente, caso necessário, este pagamento pode ser pago com outros métodos.",
"$ref": "#/components/schemas/PaymentMethods",
"example": "credit"
},
"value": {
"description": "O valor do pagamento em centavos. Por exemplo, para R$50,00, o `value` deve ser 5000. Obrigatório se os `items` não forem informados. Se os `items` forem especificado para o pagamento, a soma do valor dos items será usada, considerando as quantidades, e este campo será ignorado.",
"type": "string"
},
"fine": {
"type": "number",
"description": "A multa do pagamento, em valor percentual. Ex.: para multa de 2% sobre o valor do pagamento vencido, envie 2."
},
"interest": {
"type": "number",
"description": "O juros do pagamento, em valor percentual. Ex.: para 2% ao mês, envie 2."
},
"custom_data": {
"description": "Objeto no formato `key-value` para armazenar juntamente ao pagamento.",
"$ref": "#/components/schemas/CustomDataItem"
},
"customer": {
"description": "Os dados do cliente",
"$ref": "#/components/schemas/Customer"
},
"items": {
"description": "Os items que compõe esse pagamento. Obrigatório se o `value` não for informado. Se os `items` forem especificado para o pagamento, a soma do valor dos items será usada, considerando as quantidades, e o `value` será ignorado mesmo que esteja presente.",
"type": "array",
"items": {
"$ref": "#/components/schemas/PaymentItem"
}
},
"fraud_prevention": {
"description": "Os dados referentes a análise antifraude, se a empresa tiver contratado este serviço.",
"$ref": "#/components/schemas/FraudPrevention"
},
"card_hash": {
"description": "O hash encriptado dos dados do cartão. Para entender o fluxo de criptografia consulte a documentação para [`hash de cartões`](/referencia/ninepay-api#encriptando-os-dados-do-cartão). Obrigatório se o método é `credit` e o `card` não foi informado.",
"type": "string",
"example": "32_wbFpoccZsXLzRTU8QojcGR5E6Sd"
},
"card": {
"description": "Os dados do cartão em formato puro. Atenção, para trafegar dados neste formato a sua infraestrutura deve ser PCI compliance. Obrigatório se o método é `credit` e o `card_hash` não foi informado.",
"$ref": "#/components/schemas/Card"
},
"installments": {
"description": "Se o método é `credit`, em quantas parcelas a compra deve ser processada.",
"type": "integer",
"minimum": 1,
"maximum": 12
},
"due_date": {
"description": "A data de vencimento da cobrança. É utilizada para o vencimento do boleto e do pix. Obrigatório se o método é `billet`.",
"type": "string",
"format": "date",
"example": "2027-07-21"
}
}
},
"Card": {
"type": "object",
"properties": {
"number": {
"description": "O número do cartão",
"type": "string",
"example": 5520392774513817
},
"holder": {
"description": "O nome do portador conforme escrito no cartão",
"type": "string",
"example": "Jhon Doe"
},
"expiration": {
"description": "A expiração do cartão",
"type": "string",
"example": "06/2029"
},
"cvv": {
"description": "o código de verificação conforme escrito no cartão",
"type": "string",
"example": 123
}
}
},
"FraudPrevention": {
"type": "object",
"properties": {
"session_id": {
"description": "O id da sessão gerado pelo script de monitoramento",
"type": "string",
"example": "EoXa4RJP3bdGk"
},
"ip": {
"description": "O IP de onde o usuário fez o pedido",
"type": "string",
"example": "163.39.202.130"
}
}
},
"PaymentItem": {
"type": "object",
"required": [
"name",
"value",
"amount"
],
"properties": {
"name": {
"type": "string",
"description": "O nome do item adicional",
"example": "Serviço adicional de consultoria"
},
"value": {
"type": "integer",
"description": "O valor desse item adicional. Por exemplo, para R$20,00, o `value` deve ser 2000",
"example": 2000
},
"amount": {
"type": "integer",
"description": "A quantidade do item adicional",
"example": 2
}
}
},
"CustomDataItem": {
"type": "object",
"additionalProperties": true,
"example": {
"rg": "21.526.170-7"
}
},
"PaymentMethods": {
"type": "string",
"enum": [
"credit",
"billet",
"pix"
]
}
},
"requestBodies": {
"PaymentBody": {
"required": true,
"description": "Descreve os dados a serem incluídos no corpo da requisição. **Atenção**: alguns dados deixam de ser e tornam obrigatórios de acordo com outros dados enviados juntos com a requisição. Leia atentamente a descrição de todos os campos.\n",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaymentBody"
}
}
}
}
}
},
"tags": [
{
"name": "Pagamentos",
"description": "Pagamentos"
}
],
"x-tagGroups": [
{
"name": "API Calls",
"tags": [
"Pagamentos",
"Clientes",
"Planos",
"Assinaturas",
"Consultas"
]
}
],
"servers": [
{
"url": "https://api.sandbox.cefispay.com.br/api/v1",
"description": "Servidor de Testes (sandbox)"
}
],
"security": [
{
"Bearer": []
}
]
}
```
---
# Atualizar pagamento existente
Source: https://docs.ninepay.com.br/reference/atualizar-pagamento-existente
Atualiza um pagamento existente com base no ID fornecido. **Nota:** É necessário fornecer o ID do pagamento que deseja atualizar.
# OpenAPI definition
```json
{
"openapi": "3.0.3",
"info": {
"title": "NinePay API",
"version": "1.0",
"x-logo": {
"url": ""
},
"termsOfService": "https://bit.ly/cefispay-contrato",
"contact": {
"name": "NinePay Engineering Team",
"email": "ti@ninepay.com.br"
},
"description": "# Introdução\nBem vindo a referência da **API NinePay**.\nÉ através desta API que você integra o seu sistema ao nosso.\nNossa API é RESTful, e todas suas respostas são em JSON, no endpoint base:\n```\nhttps://payments.cefis.com.br/api/v1/\n```\n\n## Ambientes\nAlém do ambiente de **produção** temos disponível o ambiente **sandbox**\npara a realização de testes de integração. Toda a comunicação com o ambiente sandbox deve ser feita através da url:\n\n```\nhttps://api.sandbox.cefispay.com.br/api/v1/\n```\n\n## Autenticação\nTodas as requisições que requerem autenticação, deverão informar no header `Authorization` o token de api enviado pela nossa equipe, observando sempre o ambiente desejado e no seguinte formato:\n```\nAuthorization: Bearer \n```\n\n## Headers\nRecomendamos que os cabeçalhos da requisições sejam corretamente adicionados para trabalhar com os tipos de dados enviados e recebidos da API:\n - Todas as requisições devem contem o header `Content-Type: application/json`, a menos que o endpoint específico defina diferente\n - Todas as requisições devem contem o header `Accept: application/json`, a menos que o endpoint específico defina diferente\n\n## Respostas\n- Os recursos vêm dentro de `data`: `GET /customers/{id}` responde `{ \"data\": { ... } }`.\n- As criações respondem **201**. `POST /payments` responde `{ \"customer\", \"payment\", \"invoice_url\" }` (o `invoice_url` só no boleto) e `POST /subscriptions` responde `{ \"customer\", \"subscription\" }`.\n- Valores sempre em centavos (inteiro): R$ 50,00 é `5000`.\n\n## Erros\nTodo erro tem o mesmo formato:\n```json\n{\n \"code\": \"VALIDATION_ERROR\",\n \"message\": \"Os dados informados são inválidos.\",\n \"errors\": { \"email\": [\"O campo email é obrigatório.\"] },\n \"timestamp\": \"2026-10-22T12:03:54+00:00\",\n \"request_id\": \"64d62d36-e797-45ed-a9d5-c203bde81032\",\n \"documentation_url\": \"https://docs.ninepay.com.br\",\n \"suggestion\": \"Corrija os campos e tente novamente.\"\n}\n```\n`errors` só vem na validação, com uma **lista** de mensagens por campo. `suggestion` vem quando há uma. Guarde o `request_id` para falar com o suporte.\n\n| `code` | HTTP | Quando |\n| --- | --- | --- |\n| `AUTHENTICATION_ERROR` | 401 | Token ausente ou inválido |\n| `FORBIDDEN_ERROR` | 403 | O recurso não é da sua empresa. Em várias rotas, um id que não existe também responde 403, para não revelar quais ids existem |\n| `COMPANYBLOCKED_ERROR` | 403 | A conta está suspensa |\n| `RESOURCE_NOT_FOUND_ERROR` | 404 | O recurso não existe |\n| `ROUTE_NOT_FOUND_ERROR` | 404 | A rota não existe |\n| `METHOD_NOT_ALLOWED_ERROR` | 405 | O método não vale para a rota (ex.: `PUT /customers` sem o id) |\n| `INVALID_STATE_ERROR` | 400 | O recurso não está num estado que permita a ação (ex.: cancelar um pagamento já pago) |\n| `VALIDATION_ERROR` | 422 | Dados inválidos; veja `errors` |\n| `REFUND_NOT_ALLOWED` | 422 | O pagamento não pode ser reembolsado |\n| `TOO_MANY_ATTEMPTS` | 429 | Muitas requisições; respeite o cabeçalho `Retry-After` |\n| `UNEXPECTED_ERROR` | 500 | Erro nosso; se repetir, fale com o suporte com o `request_id` |\n\n## Paginação\nAs listagens recebem `page` (a partir de 1) e `limit` (itens por página: **10** por padrão, de 1 a **100**). A resposta traz `data` (os itens), `links` e `meta` (`current_page`, `last_page`, `per_page`, `total`).\n\n## Datas\n- Datas de calendário (`due_date`, `next_payment`) vão como `AAAA-MM-DD` na requisição.\n- Nas respostas, os campos de data e hora aparecem em dois formatos: ISO 8601 em UTC (`2026-10-27T03:00:00.000000Z`, em `due_date` e `ref_date` do pagamento) e `AAAA-MM-DD HH:MM:SS` no horário de Brasília (`created_at` e `updated_at`). Leia o campo pelo formato dele.\n\n## Identificadores\nCada recurso tem um `id` numérico e um `uuid`. Use o `id` nas rotas autenticadas e o **`uuid`** em tudo que é público (o link de pagamento, o checkout e o PDF do boleto).\n\n# Hash de cartões\nO hash de um cartão é uma versão criptografada de todos os dados do cartão do cliente, essa é a maneira mais segura de enviar os dados do cartão\ndo seu cliente diretamente para a gente. Abaixo vamos detalhar como ele funciona e como obter um hash a partir dos dados inseridos pelo cliente.\nÉ importante ressaltar que esse fluxo deve ser executado no front-end, seja ele web ou mobile, e que os dados do cartão do cliente nunca devem\nser enviados para o backend, já o hash do cartão pode ser enviado para o backend sem problemas.\n\n## Gerando uma encryption key\nA encryption key consiste basicamente em uma chave pública RSA usada para encriptar os dados do cartão, essa chave só pode ser usada uma vez, então\nsempre que precisar encriptar um novo cartão você precisa gerar uma nova encryption key.\n\nPara gerar uma encryption key é necessário fazer uma requisição ``POST`` para a rota ``/encryption_keys`` da API enviando como parâmetro seu\n``merchant_id``. Ela não usa o token da API (nunca o coloque no front-end): o ``merchant_id`` identifica a sua conta, e um\n``merchant_id`` que não existe responde 401.\n\nA requisição deverá ter esse formato:\n```\ncurl -X POST https://payments.cefis.com.br/api/v1/encryption_keys -H 'Content-Type: application/json' -d '{\"merchant_id\":\"SEU_MERCHANT_ID\"}'\n```\n\nComo resposta você receberá um objeto JSON no seguinte formato:\n```\n{\n \"id\": 1111,\n \"public_key\": \"-----BEGIN PUBLIC KEY-----\\n ... \\n-----END PUBLIC KEY-----\\n\",\n \"ip_address\": \"000.000.000.000\",\n \"created_at\": \"2017-07-03\",\n}\n```\n\n## Encriptando os dados do cartão\nPara encriptar os dados do cartão primeiro você precisa formatá-los de forma correta, para isso crie uma string JSON\ncontendo todos os dados do cartão no seguinte formato:\n\n```\n{\"card_number\":\"1111111111111111\",\"card_holder_name\":\"Jose Silva\",\"card_expiration_date\":\"11/2021\",\"card_cvv\":\"111\"}\n```\n\nEm seguida faça a criptografia RSA dessa string utilizando a chave pública (public_key) gerada no passo anterior, com\npadding do tipo PKCS1.\n\nApós criptografar os dados converta a string resultante para base64 e você terá um resultado parecido com esse:\n\n```\nGprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nO último passo é concatenar o id da sua encryption key (recebido como resposta da requisição anterior) com a string\nem base64 que representa os dados do cartão, da seguinte forma:\n\n``encryption_key_id + \"_\" + base64_encrypted_card``\n\nO resultado será o seu card hash:\n\n```\n1111_GprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nPronto, agora os dados do cartão do cliente já estão em um formato seguro para serem transportados pela rede, podendo\nagora ser enviados para o seu back-end dar sequência ao fluxo. Vale lembrar que cada card hash pode ser usado apenas\numa vez e além disso tem uma validade máxima de 30 minutos após a geração da encryption key. Caso seja necessário utilizar\no cartão mais de uma vez faça uma requisição para a rota de cartões e salve esse cartão vinculado ao usuário que o detém,\nassim você receberá um ID único que poderá ser usado para realizar mais transações com o mesmo cartão.\n"
},
"paths": {
"/payments/{id}": {
"put": {
"summary": "Atualizar pagamento existente",
"tags": [
"Pagamentos"
],
"description": "Atualiza um pagamento existente com base no ID fornecido. **Nota:** É necessário fornecer o ID do pagamento que deseja atualizar.\n",
"requestBody": {
"$ref": "#/components/requestBodies/PaymentBody"
},
"responses": {
"200": {
"description": "Pagamento atualizado com sucesso",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaymentUpdateResponse"
}
}
}
},
"401": {
"$ref": "#/components/responses/401"
},
"422": {
"$ref": "#/components/responses/422"
},
"500": {
"$ref": "#/components/responses/500"
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
]
}
}
},
"components": {
"securitySchemes": {
"Bearer": {
"type": "apiKey",
"in": "header",
"name": "Authorization",
"description": "Todas as requisições que requerem autenticação devem incluir no cabeçalho `Authorization` o token de API enviado pela nossa equipe. O token deve ser fornecido no seguinte formato:\n```\nAuthorization: Bearer \n```"
}
},
"responses": {
"401": {
"description": "Não autenticado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "AUTHENTICATION_ERROR",
"message": "Não autenticado.",
"timestamp": "2026-10-22T12:03:44+00:00",
"request_id": "f2a7e962-6083-4525-816e-f14d4a602e0a",
"documentation_url": "https://docs.ninepay.com.br"
}
}
}
},
"422": {
"description": "Erro na validação dos dados",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "VALIDATION_ERROR",
"message": "Os dados informados são inválidos.",
"errors": {
"email": [
"O campo email é obrigatório."
]
},
"timestamp": "2026-10-22T12:03:54+00:00",
"request_id": "64d62d36-e797-45ed-a9d5-c203bde81032",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Corrija os campos e tente novamente."
}
}
}
},
"500": {
"description": "Erro inesperado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "UNEXPECTED_ERROR",
"message": "Houve um erro inesperado.",
"timestamp": "2026-10-22T12:04:46+00:00",
"request_id": "868443d3-38fd-4c92-8ea8-7cccbbce4308",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Verifique todos os parâmetros da requisição. Se o erro persistir, entre em contato com nossa equipe em ti@ninepay.com.br."
}
}
}
}
},
"schemas": {
"ApiError": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "O código do erro. Ex.: `VALIDATION_ERROR`, `FORBIDDEN_ERROR`, `UNEXPECTED_ERROR`."
},
"message": {
"type": "string",
"description": "A mensagem do erro."
},
"errors": {
"type": "object",
"description": "Os erros de cada campo, quando o `code` é `VALIDATION_ERROR`.",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "A data e hora do erro, em UTC."
},
"request_id": {
"type": "string",
"description": "Um identificador único gerado para esta resposta de erro."
},
"documentation_url": {
"type": "string",
"description": "O endereço desta documentação."
},
"suggestion": {
"type": "string",
"description": "Uma sugestão de como resolver o erro."
}
}
},
"PaymentUpdateResponse": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "O ID do pagamento."
},
"uuid": {
"type": "string",
"description": "O UUID do pagamento."
},
"customer_id": {
"type": "string",
"description": "O ID do cliente do pagamento."
},
"customer": {
"type": "object",
"description": "O cliente do pagamento."
},
"subscription_id": {
"type": "string",
"description": "O ID da assinatura do pagamento."
},
"subscription": {
"type": "object",
"description": "A assinatura do pagamento."
},
"payment_link": {
"type": "object",
"description": "O link de pagamento."
},
"items": {
"type": "array",
"description": "Os itens do pagamento."
},
"allowed_methods": {
"type": "array",
"description": "Os métodos com que o cliente pode pagar este pagamento.",
"items": {
"$ref": "#/components/schemas/PaymentMethods"
}
},
"method": {
"$ref": "#/components/schemas/PaymentResponseMethods"
},
"card_id": {
"type": "string",
"description": "O ID do cartão do pagamento."
},
"card": {
"type": "object",
"description": "O cartão do pagamento."
},
"digitable_line": {
"type": "string",
"description": "A linha digitável do boleto. Só é preenchida para o método `billet`."
},
"pix_payload": {
"type": "string",
"description": "O código Pix copia e cola do pagamento. Só é preenchido para o método `pix`."
},
"custom_data": {
"type": "object",
"description": "Os dados personalizados do pagamento."
},
"value": {
"type": "number",
"description": "O valor original do pagamento em centavos, sem multa e juros. Ex.: 5000 para R$50,00."
},
"fine": {
"type": "number",
"description": "A multa do pagamento, em valor percentual. Ex.: 2 para multa de 2% sobre o valor do pagamento vencido."
},
"interest": {
"type": "number",
"description": "O juros do pagamento, em valor percentual ao mês. Ex.: 2 para 2% ao mês."
},
"current_value": {
"type": "number",
"description": "O valor a ser pago hoje, em centavos: `value` somado a `current_fine` e `current_interest`."
},
"current_fine": {
"type": "number",
"description": "O valor da multa aplicada até hoje, em centavos. É 0 enquanto o pagamento não vence."
},
"current_interest": {
"type": "number",
"description": "O valor dos juros acumulados até hoje, em centavos. É 0 enquanto o pagamento não vence."
},
"installments": {
"type": "number",
"description": "O número de parcelas do pagamento. Só se aplica ao método `credit`."
},
"status": {
"$ref": "#/components/schemas/PaymentStatus"
},
"retries_number": {
"type": "number",
"description": "O número de tentativas do pagamento."
},
"was_last_retry": {
"type": "boolean",
"description": "Se foi a última tentativa do pagamento."
},
"can_refund": {
"type": "boolean",
"description": "Se o pagamento pode ser reembolsado agora. Só é `true` quando o `status` é `paid` e o método é `credit` (até 350 dias após o pagamento) ou `pix` (até 90 dias após o pagamento)."
},
"refunds": {
"type": "array",
"description": "Os reembolsos solicitados para o pagamento. Só é retornado no endpoint de obter detalhes do pagamento quando a requisição inclui `with[]=refunds`.",
"items": {
"$ref": "#/components/schemas/PaymentRefund"
}
},
"receipts": {
"type": "array",
"description": "Os recibos do pagamento."
},
"receipt_status": {
"$ref": "#/components/schemas/ReceiptStatus"
},
"due_date": {
"type": "string",
"format": "date",
"description": "A data de vencimento do pagamento."
},
"ref_date": {
"type": "string",
"format": "date",
"description": "A data de referência do pagamento."
},
"paid_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o pagamento foi pago. É nula enquanto o `status` não é `paid`."
},
"company": {
"type": "object",
"description": "A empresa do pagamento."
},
"charge_enabled": {
"type": "boolean",
"description": "A habilitação da cobrança do pagamento."
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o pagamento foi criado."
},
"updated_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o pagamento foi atualizado."
},
"url": {
"type": "string",
"description": "A URL do pagamento."
},
"receipt_url": {
"type": "string",
"description": "A URL do recibo do pagamento."
}
}
},
"ReceiptStatus": {
"type": "integer",
"enum": [
0,
1,
2,
3,
4
],
"description": "- 0: Emissão de recibo não configurada. - 1: Recibo ainda não emitido. - 2: Recibo emitido. - 3: Erro na emissão do recibo. - 4: Emissão do recibo ignorada.\n"
},
"PaymentRefund": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"description": "O ID do reembolso."
},
"method": {
"type": "string",
"description": "O método do pagamento reembolsado: `credit` ou `pix`."
},
"value": {
"type": "number",
"description": "O valor reembolsado, em centavos."
},
"status": {
"$ref": "#/components/schemas/RefundStatus"
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o reembolso foi solicitado."
},
"updated_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora da última atualização do reembolso."
}
}
},
"RefundStatus": {
"type": "string",
"enum": [
"new",
"processing",
"completed",
"failed"
],
"description": "- new: Reembolso criado, ainda não enviado à adquirente. - processing: Reembolso em processamento na adquirente. - completed: Reembolso concluído; o valor foi devolvido ao cliente. - failed: A adquirente não conseguiu fazer o reembolso.\n"
},
"PaymentStatus": {
"type": "string",
"enum": [
"unpaid",
"paid",
"unauthorized",
"canceled",
"reversed"
],
"description": "- unpaid: Em aberto, aguardando pagamento. - paid: Pago. - unauthorized: Recusado. A tentativa de cobrança no cartão não foi autorizada; o pagamento continua em aberto e pode ser pago novamente. - canceled: Cancelado. - reversed: Estornado.\n"
},
"PaymentResponseMethods": {
"type": "string",
"enum": [
"credit",
"debit",
"billet",
"pix",
"payment_initiation",
"manual"
],
"description": "- credit: Cartão de crédito. - debit: Cartão de débito. - billet: Boleto. - pix: Pix. - payment_initiation: Iniciação de pagamento via Open Finance. - manual: Baixa manual, registrada pelo endpoint de dar baixa em pagamento.\n"
},
"PaymentMethods": {
"type": "string",
"enum": [
"credit",
"billet",
"pix"
]
},
"PaymentBody": {
"type": "object",
"required": [
"method",
"customer"
],
"properties": {
"method": {
"description": "O método que será usado para este pagamento. Posteriormente, caso necessário, este pagamento pode ser pago com outros métodos.",
"$ref": "#/components/schemas/PaymentMethods",
"example": "credit"
},
"value": {
"description": "O valor do pagamento em centavos. Por exemplo, para R$50,00, o `value` deve ser 5000. Obrigatório se os `items` não forem informados. Se os `items` forem especificado para o pagamento, a soma do valor dos items será usada, considerando as quantidades, e este campo será ignorado.",
"type": "string"
},
"fine": {
"type": "number",
"description": "A multa do pagamento, em valor percentual. Ex.: para multa de 2% sobre o valor do pagamento vencido, envie 2."
},
"interest": {
"type": "number",
"description": "O juros do pagamento, em valor percentual. Ex.: para 2% ao mês, envie 2."
},
"custom_data": {
"description": "Objeto no formato `key-value` para armazenar juntamente ao pagamento.",
"$ref": "#/components/schemas/CustomDataItem"
},
"customer": {
"description": "Os dados do cliente",
"$ref": "#/components/schemas/Customer"
},
"items": {
"description": "Os items que compõe esse pagamento. Obrigatório se o `value` não for informado. Se os `items` forem especificado para o pagamento, a soma do valor dos items será usada, considerando as quantidades, e o `value` será ignorado mesmo que esteja presente.",
"type": "array",
"items": {
"$ref": "#/components/schemas/PaymentItem"
}
},
"fraud_prevention": {
"description": "Os dados referentes a análise antifraude, se a empresa tiver contratado este serviço.",
"$ref": "#/components/schemas/FraudPrevention"
},
"card_hash": {
"description": "O hash encriptado dos dados do cartão. Para entender o fluxo de criptografia consulte a documentação para [`hash de cartões`](/referencia/ninepay-api#encriptando-os-dados-do-cartão). Obrigatório se o método é `credit` e o `card` não foi informado.",
"type": "string",
"example": "32_wbFpoccZsXLzRTU8QojcGR5E6Sd"
},
"card": {
"description": "Os dados do cartão em formato puro. Atenção, para trafegar dados neste formato a sua infraestrutura deve ser PCI compliance. Obrigatório se o método é `credit` e o `card_hash` não foi informado.",
"$ref": "#/components/schemas/Card"
},
"installments": {
"description": "Se o método é `credit`, em quantas parcelas a compra deve ser processada.",
"type": "integer",
"minimum": 1,
"maximum": 12
},
"due_date": {
"description": "A data de vencimento da cobrança. É utilizada para o vencimento do boleto e do pix. Obrigatório se o método é `billet`.",
"type": "string",
"format": "date",
"example": "2027-07-21"
}
}
},
"Card": {
"type": "object",
"properties": {
"number": {
"description": "O número do cartão",
"type": "string",
"example": 5520392774513817
},
"holder": {
"description": "O nome do portador conforme escrito no cartão",
"type": "string",
"example": "Jhon Doe"
},
"expiration": {
"description": "A expiração do cartão",
"type": "string",
"example": "06/2029"
},
"cvv": {
"description": "o código de verificação conforme escrito no cartão",
"type": "string",
"example": 123
}
}
},
"FraudPrevention": {
"type": "object",
"properties": {
"session_id": {
"description": "O id da sessão gerado pelo script de monitoramento",
"type": "string",
"example": "EoXa4RJP3bdGk"
},
"ip": {
"description": "O IP de onde o usuário fez o pedido",
"type": "string",
"example": "163.39.202.130"
}
}
},
"PaymentItem": {
"type": "object",
"required": [
"name",
"value",
"amount"
],
"properties": {
"name": {
"type": "string",
"description": "O nome do item adicional",
"example": "Serviço adicional de consultoria"
},
"value": {
"type": "integer",
"description": "O valor desse item adicional. Por exemplo, para R$20,00, o `value` deve ser 2000",
"example": 2000
},
"amount": {
"type": "integer",
"description": "A quantidade do item adicional",
"example": 2
}
}
},
"Customer": {
"type": "object",
"required": [
"id",
"name",
"email",
"cpf",
"cnpj"
],
"properties": {
"id": {
"description": "O id do cliente na NinePay. Obrigatório se os demais dados do usuário não forem informados",
"type": "integer",
"example": 42,
"readOnly": true
},
"name": {
"description": "O nome do cliente. Obrigatório se o `id` não for informado",
"type": "string",
"example": "Jhon Doe"
},
"email": {
"description": "O email do cliente. Obrigatório se o `id` não for informado",
"type": "string",
"example": "jhon@doe.com"
},
"cpf": {
"description": "O cpf do cliente. Obrigatório se o `id` ou o `cnpj` não forem informados",
"type": "string",
"example": "833.828.600-15"
},
"cnpj": {
"description": "O cnpj do cliente. Obrigatório se o `id` ou o `cpf` não forem informados",
"type": "string",
"example": "95.135.209/0001-79"
},
"phone": {
"description": "O telefone celular do cliente, com DDD. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": "(11) 11111-1111"
},
"cep": {
"description": "O CEP do cliente. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": "01423-910"
},
"address": {
"description": "O endereço do cliente",
"type": "string",
"example": "Rua José Maria Lisboa"
},
"number": {
"description": "O número do endereço do cliente. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": 42
},
"district": {
"description": "O bairro do cliente",
"type": "string",
"example": "Jardim Paulista"
},
"city": {
"description": "A cidade do cliente",
"type": "string",
"example": "São Paulo"
},
"state": {
"description": "O estado do cliente",
"type": "string",
"example": "SP"
},
"country": {
"description": "O código do país do cliente, no formato Alpha 2 de acordo com a [ISO 3166](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes).",
"type": "string",
"example": "BR"
}
}
},
"CustomDataItem": {
"type": "object",
"additionalProperties": true,
"example": {
"rg": "21.526.170-7"
}
}
},
"requestBodies": {
"PaymentBody": {
"required": true,
"description": "Descreve os dados a serem incluídos no corpo da requisição. **Atenção**: alguns dados deixam de ser e tornam obrigatórios de acordo com outros dados enviados juntos com a requisição. Leia atentamente a descrição de todos os campos.\n",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaymentBody"
}
}
}
}
}
},
"tags": [
{
"name": "Pagamentos",
"description": "Pagamentos"
}
],
"x-tagGroups": [
{
"name": "API Calls",
"tags": [
"Pagamentos",
"Clientes",
"Planos",
"Assinaturas",
"Consultas"
]
}
],
"servers": [
{
"url": "https://api.sandbox.cefispay.com.br/api/v1",
"description": "Servidor de Testes (sandbox)"
}
],
"security": [
{
"Bearer": []
}
]
}
```
---
# Obter detalhes do pagamento
Source: https://docs.ninepay.com.br/reference/obter-detalhes-do-pagamento
Retorna os detalhes de um pagamento específico, com base no ID fornecido. **Nota:** É necessário fornecer o ID do pagamento para obter os detalhes.
# OpenAPI definition
```json
{
"openapi": "3.0.3",
"info": {
"title": "NinePay API",
"version": "1.0",
"x-logo": {
"url": ""
},
"termsOfService": "https://bit.ly/cefispay-contrato",
"contact": {
"name": "NinePay Engineering Team",
"email": "ti@ninepay.com.br"
},
"description": "# Introdução\nBem vindo a referência da **API NinePay**.\nÉ através desta API que você integra o seu sistema ao nosso.\nNossa API é RESTful, e todas suas respostas são em JSON, no endpoint base:\n```\nhttps://payments.cefis.com.br/api/v1/\n```\n\n## Ambientes\nAlém do ambiente de **produção** temos disponível o ambiente **sandbox**\npara a realização de testes de integração. Toda a comunicação com o ambiente sandbox deve ser feita através da url:\n\n```\nhttps://api.sandbox.cefispay.com.br/api/v1/\n```\n\n## Autenticação\nTodas as requisições que requerem autenticação, deverão informar no header `Authorization` o token de api enviado pela nossa equipe, observando sempre o ambiente desejado e no seguinte formato:\n```\nAuthorization: Bearer \n```\n\n## Headers\nRecomendamos que os cabeçalhos da requisições sejam corretamente adicionados para trabalhar com os tipos de dados enviados e recebidos da API:\n - Todas as requisições devem contem o header `Content-Type: application/json`, a menos que o endpoint específico defina diferente\n - Todas as requisições devem contem o header `Accept: application/json`, a menos que o endpoint específico defina diferente\n\n## Respostas\n- Os recursos vêm dentro de `data`: `GET /customers/{id}` responde `{ \"data\": { ... } }`.\n- As criações respondem **201**. `POST /payments` responde `{ \"customer\", \"payment\", \"invoice_url\" }` (o `invoice_url` só no boleto) e `POST /subscriptions` responde `{ \"customer\", \"subscription\" }`.\n- Valores sempre em centavos (inteiro): R$ 50,00 é `5000`.\n\n## Erros\nTodo erro tem o mesmo formato:\n```json\n{\n \"code\": \"VALIDATION_ERROR\",\n \"message\": \"Os dados informados são inválidos.\",\n \"errors\": { \"email\": [\"O campo email é obrigatório.\"] },\n \"timestamp\": \"2026-10-22T12:03:54+00:00\",\n \"request_id\": \"64d62d36-e797-45ed-a9d5-c203bde81032\",\n \"documentation_url\": \"https://docs.ninepay.com.br\",\n \"suggestion\": \"Corrija os campos e tente novamente.\"\n}\n```\n`errors` só vem na validação, com uma **lista** de mensagens por campo. `suggestion` vem quando há uma. Guarde o `request_id` para falar com o suporte.\n\n| `code` | HTTP | Quando |\n| --- | --- | --- |\n| `AUTHENTICATION_ERROR` | 401 | Token ausente ou inválido |\n| `FORBIDDEN_ERROR` | 403 | O recurso não é da sua empresa. Em várias rotas, um id que não existe também responde 403, para não revelar quais ids existem |\n| `COMPANYBLOCKED_ERROR` | 403 | A conta está suspensa |\n| `RESOURCE_NOT_FOUND_ERROR` | 404 | O recurso não existe |\n| `ROUTE_NOT_FOUND_ERROR` | 404 | A rota não existe |\n| `METHOD_NOT_ALLOWED_ERROR` | 405 | O método não vale para a rota (ex.: `PUT /customers` sem o id) |\n| `INVALID_STATE_ERROR` | 400 | O recurso não está num estado que permita a ação (ex.: cancelar um pagamento já pago) |\n| `VALIDATION_ERROR` | 422 | Dados inválidos; veja `errors` |\n| `REFUND_NOT_ALLOWED` | 422 | O pagamento não pode ser reembolsado |\n| `TOO_MANY_ATTEMPTS` | 429 | Muitas requisições; respeite o cabeçalho `Retry-After` |\n| `UNEXPECTED_ERROR` | 500 | Erro nosso; se repetir, fale com o suporte com o `request_id` |\n\n## Paginação\nAs listagens recebem `page` (a partir de 1) e `limit` (itens por página: **10** por padrão, de 1 a **100**). A resposta traz `data` (os itens), `links` e `meta` (`current_page`, `last_page`, `per_page`, `total`).\n\n## Datas\n- Datas de calendário (`due_date`, `next_payment`) vão como `AAAA-MM-DD` na requisição.\n- Nas respostas, os campos de data e hora aparecem em dois formatos: ISO 8601 em UTC (`2026-10-27T03:00:00.000000Z`, em `due_date` e `ref_date` do pagamento) e `AAAA-MM-DD HH:MM:SS` no horário de Brasília (`created_at` e `updated_at`). Leia o campo pelo formato dele.\n\n## Identificadores\nCada recurso tem um `id` numérico e um `uuid`. Use o `id` nas rotas autenticadas e o **`uuid`** em tudo que é público (o link de pagamento, o checkout e o PDF do boleto).\n\n# Hash de cartões\nO hash de um cartão é uma versão criptografada de todos os dados do cartão do cliente, essa é a maneira mais segura de enviar os dados do cartão\ndo seu cliente diretamente para a gente. Abaixo vamos detalhar como ele funciona e como obter um hash a partir dos dados inseridos pelo cliente.\nÉ importante ressaltar que esse fluxo deve ser executado no front-end, seja ele web ou mobile, e que os dados do cartão do cliente nunca devem\nser enviados para o backend, já o hash do cartão pode ser enviado para o backend sem problemas.\n\n## Gerando uma encryption key\nA encryption key consiste basicamente em uma chave pública RSA usada para encriptar os dados do cartão, essa chave só pode ser usada uma vez, então\nsempre que precisar encriptar um novo cartão você precisa gerar uma nova encryption key.\n\nPara gerar uma encryption key é necessário fazer uma requisição ``POST`` para a rota ``/encryption_keys`` da API enviando como parâmetro seu\n``merchant_id``. Ela não usa o token da API (nunca o coloque no front-end): o ``merchant_id`` identifica a sua conta, e um\n``merchant_id`` que não existe responde 401.\n\nA requisição deverá ter esse formato:\n```\ncurl -X POST https://payments.cefis.com.br/api/v1/encryption_keys -H 'Content-Type: application/json' -d '{\"merchant_id\":\"SEU_MERCHANT_ID\"}'\n```\n\nComo resposta você receberá um objeto JSON no seguinte formato:\n```\n{\n \"id\": 1111,\n \"public_key\": \"-----BEGIN PUBLIC KEY-----\\n ... \\n-----END PUBLIC KEY-----\\n\",\n \"ip_address\": \"000.000.000.000\",\n \"created_at\": \"2017-07-03\",\n}\n```\n\n## Encriptando os dados do cartão\nPara encriptar os dados do cartão primeiro você precisa formatá-los de forma correta, para isso crie uma string JSON\ncontendo todos os dados do cartão no seguinte formato:\n\n```\n{\"card_number\":\"1111111111111111\",\"card_holder_name\":\"Jose Silva\",\"card_expiration_date\":\"11/2021\",\"card_cvv\":\"111\"}\n```\n\nEm seguida faça a criptografia RSA dessa string utilizando a chave pública (public_key) gerada no passo anterior, com\npadding do tipo PKCS1.\n\nApós criptografar os dados converta a string resultante para base64 e você terá um resultado parecido com esse:\n\n```\nGprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nO último passo é concatenar o id da sua encryption key (recebido como resposta da requisição anterior) com a string\nem base64 que representa os dados do cartão, da seguinte forma:\n\n``encryption_key_id + \"_\" + base64_encrypted_card``\n\nO resultado será o seu card hash:\n\n```\n1111_GprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nPronto, agora os dados do cartão do cliente já estão em um formato seguro para serem transportados pela rede, podendo\nagora ser enviados para o seu back-end dar sequência ao fluxo. Vale lembrar que cada card hash pode ser usado apenas\numa vez e além disso tem uma validade máxima de 30 minutos após a geração da encryption key. Caso seja necessário utilizar\no cartão mais de uma vez faça uma requisição para a rota de cartões e salve esse cartão vinculado ao usuário que o detém,\nassim você receberá um ID único que poderá ser usado para realizar mais transações com o mesmo cartão.\n"
},
"paths": {
"/payments/{id}": {
"get": {
"summary": "Obter detalhes do pagamento",
"tags": [
"Pagamentos"
],
"description": "Retorna os detalhes de um pagamento específico, com base no ID fornecido. **Nota:** É necessário fornecer o ID do pagamento para obter os detalhes.\n",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"description": "O ID do pagamento.",
"schema": {
"type": "integer"
}
},
{
"name": "with[]",
"in": "query",
"required": false,
"description": "Os dados relacionados a incluir na resposta. Envie o parâmetro uma vez para cada valor. Ex.: `?with[]=customer&with[]=refunds`. Use `refunds` para acompanhar um reembolso.",
"style": "form",
"explode": true,
"schema": {
"type": "array",
"items": {
"type": "string",
"enum": [
"customer",
"subscription",
"card",
"payment_link",
"payment_link.custom_fields",
"items",
"refunds",
"booklet"
]
}
}
}
],
"responses": {
"200": {
"description": "Detalhes do pagamento retornados com sucesso",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaymentDetailsResponse"
}
}
}
},
"401": {
"$ref": "#/components/responses/401"
},
"422": {
"$ref": "#/components/responses/422"
},
"500": {
"$ref": "#/components/responses/500"
}
},
"operationId": "getPayment"
}
}
},
"components": {
"securitySchemes": {
"Bearer": {
"type": "apiKey",
"in": "header",
"name": "Authorization",
"description": "Todas as requisições que requerem autenticação devem incluir no cabeçalho `Authorization` o token de API enviado pela nossa equipe. O token deve ser fornecido no seguinte formato:\n```\nAuthorization: Bearer \n```"
}
},
"responses": {
"401": {
"description": "Não autenticado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "AUTHENTICATION_ERROR",
"message": "Não autenticado.",
"timestamp": "2026-10-22T12:03:44+00:00",
"request_id": "f2a7e962-6083-4525-816e-f14d4a602e0a",
"documentation_url": "https://docs.ninepay.com.br"
}
}
}
},
"422": {
"description": "Erro na validação dos dados",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "VALIDATION_ERROR",
"message": "Os dados informados são inválidos.",
"errors": {
"email": [
"O campo email é obrigatório."
]
},
"timestamp": "2026-10-22T12:03:54+00:00",
"request_id": "64d62d36-e797-45ed-a9d5-c203bde81032",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Corrija os campos e tente novamente."
}
}
}
},
"500": {
"description": "Erro inesperado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "UNEXPECTED_ERROR",
"message": "Houve um erro inesperado.",
"timestamp": "2026-10-22T12:04:46+00:00",
"request_id": "868443d3-38fd-4c92-8ea8-7cccbbce4308",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Verifique todos os parâmetros da requisição. Se o erro persistir, entre em contato com nossa equipe em ti@ninepay.com.br."
}
}
}
}
},
"schemas": {
"ApiError": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "O código do erro. Ex.: `VALIDATION_ERROR`, `FORBIDDEN_ERROR`, `UNEXPECTED_ERROR`."
},
"message": {
"type": "string",
"description": "A mensagem do erro."
},
"errors": {
"type": "object",
"description": "Os erros de cada campo, quando o `code` é `VALIDATION_ERROR`.",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "A data e hora do erro, em UTC."
},
"request_id": {
"type": "string",
"description": "Um identificador único gerado para esta resposta de erro."
},
"documentation_url": {
"type": "string",
"description": "O endereço desta documentação."
},
"suggestion": {
"type": "string",
"description": "Uma sugestão de como resolver o erro."
}
}
},
"PaymentDetailsResponse": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "O ID do pagamento."
},
"uuid": {
"type": "string",
"description": "O UUID do pagamento."
},
"customer_id": {
"type": "string",
"description": "O ID do cliente do pagamento."
},
"customer": {
"type": "object",
"description": "O cliente do pagamento."
},
"subscription_id": {
"type": "string",
"description": "O ID da assinatura do pagamento."
},
"subscription": {
"type": "object",
"description": "A assinatura do pagamento."
},
"payment_link": {
"type": "object",
"description": "O link de pagamento."
},
"items": {
"type": "array",
"description": "Os itens do pagamento."
},
"allowed_methods": {
"type": "array",
"description": "Os métodos com que o cliente pode pagar este pagamento.",
"items": {
"$ref": "#/components/schemas/PaymentMethods"
}
},
"method": {
"$ref": "#/components/schemas/PaymentResponseMethods"
},
"card_id": {
"type": "string",
"description": "O ID do cartão do pagamento."
},
"card": {
"type": "object",
"description": "O cartão do pagamento."
},
"digitable_line": {
"type": "string",
"description": "A linha digitável do boleto. Só é preenchida para o método `billet`."
},
"pix_payload": {
"type": "string",
"description": "O código Pix copia e cola do pagamento. Só é preenchido para o método `pix`."
},
"custom_data": {
"type": "object",
"description": "Os dados personalizados do pagamento."
},
"value": {
"type": "number",
"description": "O valor original do pagamento em centavos, sem multa e juros. Ex.: 5000 para R$50,00."
},
"fine": {
"type": "number",
"description": "A multa do pagamento, em valor percentual. Ex.: 2 para multa de 2% sobre o valor do pagamento vencido."
},
"interest": {
"type": "number",
"description": "O juros do pagamento, em valor percentual ao mês. Ex.: 2 para 2% ao mês."
},
"current_value": {
"type": "number",
"description": "O valor a ser pago hoje, em centavos: `value` somado a `current_fine` e `current_interest`."
},
"current_fine": {
"type": "number",
"description": "O valor da multa aplicada até hoje, em centavos. É 0 enquanto o pagamento não vence."
},
"current_interest": {
"type": "number",
"description": "O valor dos juros acumulados até hoje, em centavos. É 0 enquanto o pagamento não vence."
},
"installments": {
"type": "number",
"description": "O número de parcelas do pagamento. Só se aplica ao método `credit`."
},
"status": {
"$ref": "#/components/schemas/PaymentStatus"
},
"retries_number": {
"type": "number",
"description": "O número de tentativas do pagamento."
},
"was_last_retry": {
"type": "boolean",
"description": "Se foi a última tentativa do pagamento."
},
"can_refund": {
"type": "boolean",
"description": "Se o pagamento pode ser reembolsado agora. Só é `true` quando o `status` é `paid` e o método é `credit` (até 350 dias após o pagamento) ou `pix` (até 90 dias após o pagamento)."
},
"refunds": {
"type": "array",
"description": "Os reembolsos solicitados para o pagamento. Só é retornado no endpoint de obter detalhes do pagamento quando a requisição inclui `with[]=refunds`.",
"items": {
"$ref": "#/components/schemas/PaymentRefund"
}
},
"receipts": {
"type": "array",
"description": "Os recibos do pagamento."
},
"receipt_status": {
"$ref": "#/components/schemas/ReceiptStatus"
},
"due_date": {
"type": "string",
"format": "date",
"description": "A data de vencimento do pagamento."
},
"ref_date": {
"type": "string",
"format": "date",
"description": "A data de referência do pagamento."
},
"paid_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o pagamento foi pago. É nula enquanto o `status` não é `paid`."
},
"company": {
"type": "object",
"description": "A empresa do pagamento."
},
"charge_enabled": {
"type": "boolean",
"description": "A habilitação da cobrança do pagamento."
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o pagamento foi criado."
},
"updated_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o pagamento foi atualizado."
},
"url": {
"type": "string",
"description": "A URL do pagamento."
},
"receipt_url": {
"type": "string",
"description": "A URL do recibo do pagamento."
}
}
},
"ReceiptStatus": {
"type": "integer",
"enum": [
0,
1,
2,
3,
4
],
"description": "- 0: Emissão de recibo não configurada. - 1: Recibo ainda não emitido. - 2: Recibo emitido. - 3: Erro na emissão do recibo. - 4: Emissão do recibo ignorada.\n"
},
"PaymentRefund": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"description": "O ID do reembolso."
},
"method": {
"type": "string",
"description": "O método do pagamento reembolsado: `credit` ou `pix`."
},
"value": {
"type": "number",
"description": "O valor reembolsado, em centavos."
},
"status": {
"$ref": "#/components/schemas/RefundStatus"
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o reembolso foi solicitado."
},
"updated_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora da última atualização do reembolso."
}
}
},
"RefundStatus": {
"type": "string",
"enum": [
"new",
"processing",
"completed",
"failed"
],
"description": "- new: Reembolso criado, ainda não enviado à adquirente. - processing: Reembolso em processamento na adquirente. - completed: Reembolso concluído; o valor foi devolvido ao cliente. - failed: A adquirente não conseguiu fazer o reembolso.\n"
},
"PaymentStatus": {
"type": "string",
"enum": [
"unpaid",
"paid",
"unauthorized",
"canceled",
"reversed"
],
"description": "- unpaid: Em aberto, aguardando pagamento. - paid: Pago. - unauthorized: Recusado. A tentativa de cobrança no cartão não foi autorizada; o pagamento continua em aberto e pode ser pago novamente. - canceled: Cancelado. - reversed: Estornado.\n"
},
"PaymentResponseMethods": {
"type": "string",
"enum": [
"credit",
"debit",
"billet",
"pix",
"payment_initiation",
"manual"
],
"description": "- credit: Cartão de crédito. - debit: Cartão de débito. - billet: Boleto. - pix: Pix. - payment_initiation: Iniciação de pagamento via Open Finance. - manual: Baixa manual, registrada pelo endpoint de dar baixa em pagamento.\n"
},
"PaymentMethods": {
"type": "string",
"enum": [
"credit",
"billet",
"pix"
]
}
}
},
"tags": [
{
"name": "Pagamentos",
"description": "Pagamentos"
}
],
"x-tagGroups": [
{
"name": "API Calls",
"tags": [
"Pagamentos",
"Clientes",
"Planos",
"Assinaturas",
"Consultas"
]
}
],
"servers": [
{
"url": "https://api.sandbox.cefispay.com.br/api/v1",
"description": "Servidor de Testes (sandbox)"
}
],
"security": [
{
"Bearer": []
}
]
}
```
---
# Cancelar um pagamento
Source: https://docs.ninepay.com.br/reference/cancelar-um-pagamento
Cancela o pagamento com base no ID fornecido. Um pagamento cancelado não gera mais envio de comunicações ao cliente. Caso seja um pagamento de assinatura, o sistema irá considerar o pagamento como pago a fim de determinar o status da assinatura.
# OpenAPI definition
```json
{
"openapi": "3.0.3",
"info": {
"title": "NinePay API",
"version": "1.0",
"x-logo": {
"url": ""
},
"termsOfService": "https://bit.ly/cefispay-contrato",
"contact": {
"name": "NinePay Engineering Team",
"email": "ti@ninepay.com.br"
},
"description": "# Introdução\nBem vindo a referência da **API NinePay**.\nÉ através desta API que você integra o seu sistema ao nosso.\nNossa API é RESTful, e todas suas respostas são em JSON, no endpoint base:\n```\nhttps://payments.cefis.com.br/api/v1/\n```\n\n## Ambientes\nAlém do ambiente de **produção** temos disponível o ambiente **sandbox**\npara a realização de testes de integração. Toda a comunicação com o ambiente sandbox deve ser feita através da url:\n\n```\nhttps://api.sandbox.cefispay.com.br/api/v1/\n```\n\n## Autenticação\nTodas as requisições que requerem autenticação, deverão informar no header `Authorization` o token de api enviado pela nossa equipe, observando sempre o ambiente desejado e no seguinte formato:\n```\nAuthorization: Bearer \n```\n\n## Headers\nRecomendamos que os cabeçalhos da requisições sejam corretamente adicionados para trabalhar com os tipos de dados enviados e recebidos da API:\n - Todas as requisições devem contem o header `Content-Type: application/json`, a menos que o endpoint específico defina diferente\n - Todas as requisições devem contem o header `Accept: application/json`, a menos que o endpoint específico defina diferente\n\n## Respostas\n- Os recursos vêm dentro de `data`: `GET /customers/{id}` responde `{ \"data\": { ... } }`.\n- As criações respondem **201**. `POST /payments` responde `{ \"customer\", \"payment\", \"invoice_url\" }` (o `invoice_url` só no boleto) e `POST /subscriptions` responde `{ \"customer\", \"subscription\" }`.\n- Valores sempre em centavos (inteiro): R$ 50,00 é `5000`.\n\n## Erros\nTodo erro tem o mesmo formato:\n```json\n{\n \"code\": \"VALIDATION_ERROR\",\n \"message\": \"Os dados informados são inválidos.\",\n \"errors\": { \"email\": [\"O campo email é obrigatório.\"] },\n \"timestamp\": \"2026-10-22T12:03:54+00:00\",\n \"request_id\": \"64d62d36-e797-45ed-a9d5-c203bde81032\",\n \"documentation_url\": \"https://docs.ninepay.com.br\",\n \"suggestion\": \"Corrija os campos e tente novamente.\"\n}\n```\n`errors` só vem na validação, com uma **lista** de mensagens por campo. `suggestion` vem quando há uma. Guarde o `request_id` para falar com o suporte.\n\n| `code` | HTTP | Quando |\n| --- | --- | --- |\n| `AUTHENTICATION_ERROR` | 401 | Token ausente ou inválido |\n| `FORBIDDEN_ERROR` | 403 | O recurso não é da sua empresa. Em várias rotas, um id que não existe também responde 403, para não revelar quais ids existem |\n| `COMPANYBLOCKED_ERROR` | 403 | A conta está suspensa |\n| `RESOURCE_NOT_FOUND_ERROR` | 404 | O recurso não existe |\n| `ROUTE_NOT_FOUND_ERROR` | 404 | A rota não existe |\n| `METHOD_NOT_ALLOWED_ERROR` | 405 | O método não vale para a rota (ex.: `PUT /customers` sem o id) |\n| `INVALID_STATE_ERROR` | 400 | O recurso não está num estado que permita a ação (ex.: cancelar um pagamento já pago) |\n| `VALIDATION_ERROR` | 422 | Dados inválidos; veja `errors` |\n| `REFUND_NOT_ALLOWED` | 422 | O pagamento não pode ser reembolsado |\n| `TOO_MANY_ATTEMPTS` | 429 | Muitas requisições; respeite o cabeçalho `Retry-After` |\n| `UNEXPECTED_ERROR` | 500 | Erro nosso; se repetir, fale com o suporte com o `request_id` |\n\n## Paginação\nAs listagens recebem `page` (a partir de 1) e `limit` (itens por página: **10** por padrão, de 1 a **100**). A resposta traz `data` (os itens), `links` e `meta` (`current_page`, `last_page`, `per_page`, `total`).\n\n## Datas\n- Datas de calendário (`due_date`, `next_payment`) vão como `AAAA-MM-DD` na requisição.\n- Nas respostas, os campos de data e hora aparecem em dois formatos: ISO 8601 em UTC (`2026-10-27T03:00:00.000000Z`, em `due_date` e `ref_date` do pagamento) e `AAAA-MM-DD HH:MM:SS` no horário de Brasília (`created_at` e `updated_at`). Leia o campo pelo formato dele.\n\n## Identificadores\nCada recurso tem um `id` numérico e um `uuid`. Use o `id` nas rotas autenticadas e o **`uuid`** em tudo que é público (o link de pagamento, o checkout e o PDF do boleto).\n\n# Hash de cartões\nO hash de um cartão é uma versão criptografada de todos os dados do cartão do cliente, essa é a maneira mais segura de enviar os dados do cartão\ndo seu cliente diretamente para a gente. Abaixo vamos detalhar como ele funciona e como obter um hash a partir dos dados inseridos pelo cliente.\nÉ importante ressaltar que esse fluxo deve ser executado no front-end, seja ele web ou mobile, e que os dados do cartão do cliente nunca devem\nser enviados para o backend, já o hash do cartão pode ser enviado para o backend sem problemas.\n\n## Gerando uma encryption key\nA encryption key consiste basicamente em uma chave pública RSA usada para encriptar os dados do cartão, essa chave só pode ser usada uma vez, então\nsempre que precisar encriptar um novo cartão você precisa gerar uma nova encryption key.\n\nPara gerar uma encryption key é necessário fazer uma requisição ``POST`` para a rota ``/encryption_keys`` da API enviando como parâmetro seu\n``merchant_id``. Ela não usa o token da API (nunca o coloque no front-end): o ``merchant_id`` identifica a sua conta, e um\n``merchant_id`` que não existe responde 401.\n\nA requisição deverá ter esse formato:\n```\ncurl -X POST https://payments.cefis.com.br/api/v1/encryption_keys -H 'Content-Type: application/json' -d '{\"merchant_id\":\"SEU_MERCHANT_ID\"}'\n```\n\nComo resposta você receberá um objeto JSON no seguinte formato:\n```\n{\n \"id\": 1111,\n \"public_key\": \"-----BEGIN PUBLIC KEY-----\\n ... \\n-----END PUBLIC KEY-----\\n\",\n \"ip_address\": \"000.000.000.000\",\n \"created_at\": \"2017-07-03\",\n}\n```\n\n## Encriptando os dados do cartão\nPara encriptar os dados do cartão primeiro você precisa formatá-los de forma correta, para isso crie uma string JSON\ncontendo todos os dados do cartão no seguinte formato:\n\n```\n{\"card_number\":\"1111111111111111\",\"card_holder_name\":\"Jose Silva\",\"card_expiration_date\":\"11/2021\",\"card_cvv\":\"111\"}\n```\n\nEm seguida faça a criptografia RSA dessa string utilizando a chave pública (public_key) gerada no passo anterior, com\npadding do tipo PKCS1.\n\nApós criptografar os dados converta a string resultante para base64 e você terá um resultado parecido com esse:\n\n```\nGprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nO último passo é concatenar o id da sua encryption key (recebido como resposta da requisição anterior) com a string\nem base64 que representa os dados do cartão, da seguinte forma:\n\n``encryption_key_id + \"_\" + base64_encrypted_card``\n\nO resultado será o seu card hash:\n\n```\n1111_GprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nPronto, agora os dados do cartão do cliente já estão em um formato seguro para serem transportados pela rede, podendo\nagora ser enviados para o seu back-end dar sequência ao fluxo. Vale lembrar que cada card hash pode ser usado apenas\numa vez e além disso tem uma validade máxima de 30 minutos após a geração da encryption key. Caso seja necessário utilizar\no cartão mais de uma vez faça uma requisição para a rota de cartões e salve esse cartão vinculado ao usuário que o detém,\nassim você receberá um ID único que poderá ser usado para realizar mais transações com o mesmo cartão.\n"
},
"paths": {
"/payments/{id}": {
"delete": {
"summary": "Cancelar um pagamento",
"tags": [
"Pagamentos"
],
"description": "Cancela o pagamento com base no ID fornecido. Um pagamento cancelado não gera mais envio de comunicações ao cliente. Caso seja um pagamento de assinatura, o sistema irá considerar o pagamento como pago a fim de determinar o status da assinatura.\n",
"parameters": [
{
"name": "id",
"in": "query",
"required": true,
"description": "O id do pagamento a ser cancelado",
"schema": {
"type": "integer"
}
},
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Pagamento cancelado com sucesso",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaymentDetailsResponse"
}
}
}
},
"401": {
"$ref": "#/components/responses/401"
},
"422": {
"$ref": "#/components/responses/422"
},
"500": {
"$ref": "#/components/responses/500"
}
}
}
}
},
"components": {
"securitySchemes": {
"Bearer": {
"type": "apiKey",
"in": "header",
"name": "Authorization",
"description": "Todas as requisições que requerem autenticação devem incluir no cabeçalho `Authorization` o token de API enviado pela nossa equipe. O token deve ser fornecido no seguinte formato:\n```\nAuthorization: Bearer \n```"
}
},
"responses": {
"401": {
"description": "Não autenticado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "AUTHENTICATION_ERROR",
"message": "Não autenticado.",
"timestamp": "2026-10-22T12:03:44+00:00",
"request_id": "f2a7e962-6083-4525-816e-f14d4a602e0a",
"documentation_url": "https://docs.ninepay.com.br"
}
}
}
},
"422": {
"description": "Erro na validação dos dados",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "VALIDATION_ERROR",
"message": "Os dados informados são inválidos.",
"errors": {
"email": [
"O campo email é obrigatório."
]
},
"timestamp": "2026-10-22T12:03:54+00:00",
"request_id": "64d62d36-e797-45ed-a9d5-c203bde81032",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Corrija os campos e tente novamente."
}
}
}
},
"500": {
"description": "Erro inesperado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "UNEXPECTED_ERROR",
"message": "Houve um erro inesperado.",
"timestamp": "2026-10-22T12:04:46+00:00",
"request_id": "868443d3-38fd-4c92-8ea8-7cccbbce4308",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Verifique todos os parâmetros da requisição. Se o erro persistir, entre em contato com nossa equipe em ti@ninepay.com.br."
}
}
}
}
},
"schemas": {
"ApiError": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "O código do erro. Ex.: `VALIDATION_ERROR`, `FORBIDDEN_ERROR`, `UNEXPECTED_ERROR`."
},
"message": {
"type": "string",
"description": "A mensagem do erro."
},
"errors": {
"type": "object",
"description": "Os erros de cada campo, quando o `code` é `VALIDATION_ERROR`.",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "A data e hora do erro, em UTC."
},
"request_id": {
"type": "string",
"description": "Um identificador único gerado para esta resposta de erro."
},
"documentation_url": {
"type": "string",
"description": "O endereço desta documentação."
},
"suggestion": {
"type": "string",
"description": "Uma sugestão de como resolver o erro."
}
}
},
"PaymentDetailsResponse": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "O ID do pagamento."
},
"uuid": {
"type": "string",
"description": "O UUID do pagamento."
},
"customer_id": {
"type": "string",
"description": "O ID do cliente do pagamento."
},
"customer": {
"type": "object",
"description": "O cliente do pagamento."
},
"subscription_id": {
"type": "string",
"description": "O ID da assinatura do pagamento."
},
"subscription": {
"type": "object",
"description": "A assinatura do pagamento."
},
"payment_link": {
"type": "object",
"description": "O link de pagamento."
},
"items": {
"type": "array",
"description": "Os itens do pagamento."
},
"allowed_methods": {
"type": "array",
"description": "Os métodos com que o cliente pode pagar este pagamento.",
"items": {
"$ref": "#/components/schemas/PaymentMethods"
}
},
"method": {
"$ref": "#/components/schemas/PaymentResponseMethods"
},
"card_id": {
"type": "string",
"description": "O ID do cartão do pagamento."
},
"card": {
"type": "object",
"description": "O cartão do pagamento."
},
"digitable_line": {
"type": "string",
"description": "A linha digitável do boleto. Só é preenchida para o método `billet`."
},
"pix_payload": {
"type": "string",
"description": "O código Pix copia e cola do pagamento. Só é preenchido para o método `pix`."
},
"custom_data": {
"type": "object",
"description": "Os dados personalizados do pagamento."
},
"value": {
"type": "number",
"description": "O valor original do pagamento em centavos, sem multa e juros. Ex.: 5000 para R$50,00."
},
"fine": {
"type": "number",
"description": "A multa do pagamento, em valor percentual. Ex.: 2 para multa de 2% sobre o valor do pagamento vencido."
},
"interest": {
"type": "number",
"description": "O juros do pagamento, em valor percentual ao mês. Ex.: 2 para 2% ao mês."
},
"current_value": {
"type": "number",
"description": "O valor a ser pago hoje, em centavos: `value` somado a `current_fine` e `current_interest`."
},
"current_fine": {
"type": "number",
"description": "O valor da multa aplicada até hoje, em centavos. É 0 enquanto o pagamento não vence."
},
"current_interest": {
"type": "number",
"description": "O valor dos juros acumulados até hoje, em centavos. É 0 enquanto o pagamento não vence."
},
"installments": {
"type": "number",
"description": "O número de parcelas do pagamento. Só se aplica ao método `credit`."
},
"status": {
"$ref": "#/components/schemas/PaymentStatus"
},
"retries_number": {
"type": "number",
"description": "O número de tentativas do pagamento."
},
"was_last_retry": {
"type": "boolean",
"description": "Se foi a última tentativa do pagamento."
},
"can_refund": {
"type": "boolean",
"description": "Se o pagamento pode ser reembolsado agora. Só é `true` quando o `status` é `paid` e o método é `credit` (até 350 dias após o pagamento) ou `pix` (até 90 dias após o pagamento)."
},
"refunds": {
"type": "array",
"description": "Os reembolsos solicitados para o pagamento. Só é retornado no endpoint de obter detalhes do pagamento quando a requisição inclui `with[]=refunds`.",
"items": {
"$ref": "#/components/schemas/PaymentRefund"
}
},
"receipts": {
"type": "array",
"description": "Os recibos do pagamento."
},
"receipt_status": {
"$ref": "#/components/schemas/ReceiptStatus"
},
"due_date": {
"type": "string",
"format": "date",
"description": "A data de vencimento do pagamento."
},
"ref_date": {
"type": "string",
"format": "date",
"description": "A data de referência do pagamento."
},
"paid_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o pagamento foi pago. É nula enquanto o `status` não é `paid`."
},
"company": {
"type": "object",
"description": "A empresa do pagamento."
},
"charge_enabled": {
"type": "boolean",
"description": "A habilitação da cobrança do pagamento."
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o pagamento foi criado."
},
"updated_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o pagamento foi atualizado."
},
"url": {
"type": "string",
"description": "A URL do pagamento."
},
"receipt_url": {
"type": "string",
"description": "A URL do recibo do pagamento."
}
}
},
"ReceiptStatus": {
"type": "integer",
"enum": [
0,
1,
2,
3,
4
],
"description": "- 0: Emissão de recibo não configurada. - 1: Recibo ainda não emitido. - 2: Recibo emitido. - 3: Erro na emissão do recibo. - 4: Emissão do recibo ignorada.\n"
},
"PaymentRefund": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"description": "O ID do reembolso."
},
"method": {
"type": "string",
"description": "O método do pagamento reembolsado: `credit` ou `pix`."
},
"value": {
"type": "number",
"description": "O valor reembolsado, em centavos."
},
"status": {
"$ref": "#/components/schemas/RefundStatus"
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o reembolso foi solicitado."
},
"updated_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora da última atualização do reembolso."
}
}
},
"RefundStatus": {
"type": "string",
"enum": [
"new",
"processing",
"completed",
"failed"
],
"description": "- new: Reembolso criado, ainda não enviado à adquirente. - processing: Reembolso em processamento na adquirente. - completed: Reembolso concluído; o valor foi devolvido ao cliente. - failed: A adquirente não conseguiu fazer o reembolso.\n"
},
"PaymentStatus": {
"type": "string",
"enum": [
"unpaid",
"paid",
"unauthorized",
"canceled",
"reversed"
],
"description": "- unpaid: Em aberto, aguardando pagamento. - paid: Pago. - unauthorized: Recusado. A tentativa de cobrança no cartão não foi autorizada; o pagamento continua em aberto e pode ser pago novamente. - canceled: Cancelado. - reversed: Estornado.\n"
},
"PaymentResponseMethods": {
"type": "string",
"enum": [
"credit",
"debit",
"billet",
"pix",
"payment_initiation",
"manual"
],
"description": "- credit: Cartão de crédito. - debit: Cartão de débito. - billet: Boleto. - pix: Pix. - payment_initiation: Iniciação de pagamento via Open Finance. - manual: Baixa manual, registrada pelo endpoint de dar baixa em pagamento.\n"
},
"PaymentMethods": {
"type": "string",
"enum": [
"credit",
"billet",
"pix"
]
}
}
},
"tags": [
{
"name": "Pagamentos",
"description": "Pagamentos"
}
],
"x-tagGroups": [
{
"name": "API Calls",
"tags": [
"Pagamentos",
"Clientes",
"Planos",
"Assinaturas",
"Consultas"
]
}
],
"servers": [
{
"url": "https://api.sandbox.cefispay.com.br/api/v1",
"description": "Servidor de Testes (sandbox)"
}
],
"security": [
{
"Bearer": []
}
]
}
```
---
# Dar baixa em pagamento
Source: https://docs.ninepay.com.br/reference/dar-baixa-em-pagamento
Marca um pagamento como pago. Utilize esta opção para registrar na NinePay um pagamento que foi feito fora do sistema, como por exemplo, um pagamento em dinheiro ou transferência bancária. Após ser marcado como pago, o cliente não receberá mais cobranças referentes a este pagamento.
# OpenAPI definition
```json
{
"openapi": "3.0.3",
"info": {
"title": "NinePay API",
"version": "1.0",
"x-logo": {
"url": ""
},
"termsOfService": "https://bit.ly/cefispay-contrato",
"contact": {
"name": "NinePay Engineering Team",
"email": "ti@ninepay.com.br"
},
"description": "# Introdução\nBem vindo a referência da **API NinePay**.\nÉ através desta API que você integra o seu sistema ao nosso.\nNossa API é RESTful, e todas suas respostas são em JSON, no endpoint base:\n```\nhttps://payments.cefis.com.br/api/v1/\n```\n\n## Ambientes\nAlém do ambiente de **produção** temos disponível o ambiente **sandbox**\npara a realização de testes de integração. Toda a comunicação com o ambiente sandbox deve ser feita através da url:\n\n```\nhttps://api.sandbox.cefispay.com.br/api/v1/\n```\n\n## Autenticação\nTodas as requisições que requerem autenticação, deverão informar no header `Authorization` o token de api enviado pela nossa equipe, observando sempre o ambiente desejado e no seguinte formato:\n```\nAuthorization: Bearer \n```\n\n## Headers\nRecomendamos que os cabeçalhos da requisições sejam corretamente adicionados para trabalhar com os tipos de dados enviados e recebidos da API:\n - Todas as requisições devem contem o header `Content-Type: application/json`, a menos que o endpoint específico defina diferente\n - Todas as requisições devem contem o header `Accept: application/json`, a menos que o endpoint específico defina diferente\n\n## Respostas\n- Os recursos vêm dentro de `data`: `GET /customers/{id}` responde `{ \"data\": { ... } }`.\n- As criações respondem **201**. `POST /payments` responde `{ \"customer\", \"payment\", \"invoice_url\" }` (o `invoice_url` só no boleto) e `POST /subscriptions` responde `{ \"customer\", \"subscription\" }`.\n- Valores sempre em centavos (inteiro): R$ 50,00 é `5000`.\n\n## Erros\nTodo erro tem o mesmo formato:\n```json\n{\n \"code\": \"VALIDATION_ERROR\",\n \"message\": \"Os dados informados são inválidos.\",\n \"errors\": { \"email\": [\"O campo email é obrigatório.\"] },\n \"timestamp\": \"2026-10-22T12:03:54+00:00\",\n \"request_id\": \"64d62d36-e797-45ed-a9d5-c203bde81032\",\n \"documentation_url\": \"https://docs.ninepay.com.br\",\n \"suggestion\": \"Corrija os campos e tente novamente.\"\n}\n```\n`errors` só vem na validação, com uma **lista** de mensagens por campo. `suggestion` vem quando há uma. Guarde o `request_id` para falar com o suporte.\n\n| `code` | HTTP | Quando |\n| --- | --- | --- |\n| `AUTHENTICATION_ERROR` | 401 | Token ausente ou inválido |\n| `FORBIDDEN_ERROR` | 403 | O recurso não é da sua empresa. Em várias rotas, um id que não existe também responde 403, para não revelar quais ids existem |\n| `COMPANYBLOCKED_ERROR` | 403 | A conta está suspensa |\n| `RESOURCE_NOT_FOUND_ERROR` | 404 | O recurso não existe |\n| `ROUTE_NOT_FOUND_ERROR` | 404 | A rota não existe |\n| `METHOD_NOT_ALLOWED_ERROR` | 405 | O método não vale para a rota (ex.: `PUT /customers` sem o id) |\n| `INVALID_STATE_ERROR` | 400 | O recurso não está num estado que permita a ação (ex.: cancelar um pagamento já pago) |\n| `VALIDATION_ERROR` | 422 | Dados inválidos; veja `errors` |\n| `REFUND_NOT_ALLOWED` | 422 | O pagamento não pode ser reembolsado |\n| `TOO_MANY_ATTEMPTS` | 429 | Muitas requisições; respeite o cabeçalho `Retry-After` |\n| `UNEXPECTED_ERROR` | 500 | Erro nosso; se repetir, fale com o suporte com o `request_id` |\n\n## Paginação\nAs listagens recebem `page` (a partir de 1) e `limit` (itens por página: **10** por padrão, de 1 a **100**). A resposta traz `data` (os itens), `links` e `meta` (`current_page`, `last_page`, `per_page`, `total`).\n\n## Datas\n- Datas de calendário (`due_date`, `next_payment`) vão como `AAAA-MM-DD` na requisição.\n- Nas respostas, os campos de data e hora aparecem em dois formatos: ISO 8601 em UTC (`2026-10-27T03:00:00.000000Z`, em `due_date` e `ref_date` do pagamento) e `AAAA-MM-DD HH:MM:SS` no horário de Brasília (`created_at` e `updated_at`). Leia o campo pelo formato dele.\n\n## Identificadores\nCada recurso tem um `id` numérico e um `uuid`. Use o `id` nas rotas autenticadas e o **`uuid`** em tudo que é público (o link de pagamento, o checkout e o PDF do boleto).\n\n# Hash de cartões\nO hash de um cartão é uma versão criptografada de todos os dados do cartão do cliente, essa é a maneira mais segura de enviar os dados do cartão\ndo seu cliente diretamente para a gente. Abaixo vamos detalhar como ele funciona e como obter um hash a partir dos dados inseridos pelo cliente.\nÉ importante ressaltar que esse fluxo deve ser executado no front-end, seja ele web ou mobile, e que os dados do cartão do cliente nunca devem\nser enviados para o backend, já o hash do cartão pode ser enviado para o backend sem problemas.\n\n## Gerando uma encryption key\nA encryption key consiste basicamente em uma chave pública RSA usada para encriptar os dados do cartão, essa chave só pode ser usada uma vez, então\nsempre que precisar encriptar um novo cartão você precisa gerar uma nova encryption key.\n\nPara gerar uma encryption key é necessário fazer uma requisição ``POST`` para a rota ``/encryption_keys`` da API enviando como parâmetro seu\n``merchant_id``. Ela não usa o token da API (nunca o coloque no front-end): o ``merchant_id`` identifica a sua conta, e um\n``merchant_id`` que não existe responde 401.\n\nA requisição deverá ter esse formato:\n```\ncurl -X POST https://payments.cefis.com.br/api/v1/encryption_keys -H 'Content-Type: application/json' -d '{\"merchant_id\":\"SEU_MERCHANT_ID\"}'\n```\n\nComo resposta você receberá um objeto JSON no seguinte formato:\n```\n{\n \"id\": 1111,\n \"public_key\": \"-----BEGIN PUBLIC KEY-----\\n ... \\n-----END PUBLIC KEY-----\\n\",\n \"ip_address\": \"000.000.000.000\",\n \"created_at\": \"2017-07-03\",\n}\n```\n\n## Encriptando os dados do cartão\nPara encriptar os dados do cartão primeiro você precisa formatá-los de forma correta, para isso crie uma string JSON\ncontendo todos os dados do cartão no seguinte formato:\n\n```\n{\"card_number\":\"1111111111111111\",\"card_holder_name\":\"Jose Silva\",\"card_expiration_date\":\"11/2021\",\"card_cvv\":\"111\"}\n```\n\nEm seguida faça a criptografia RSA dessa string utilizando a chave pública (public_key) gerada no passo anterior, com\npadding do tipo PKCS1.\n\nApós criptografar os dados converta a string resultante para base64 e você terá um resultado parecido com esse:\n\n```\nGprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nO último passo é concatenar o id da sua encryption key (recebido como resposta da requisição anterior) com a string\nem base64 que representa os dados do cartão, da seguinte forma:\n\n``encryption_key_id + \"_\" + base64_encrypted_card``\n\nO resultado será o seu card hash:\n\n```\n1111_GprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nPronto, agora os dados do cartão do cliente já estão em um formato seguro para serem transportados pela rede, podendo\nagora ser enviados para o seu back-end dar sequência ao fluxo. Vale lembrar que cada card hash pode ser usado apenas\numa vez e além disso tem uma validade máxima de 30 minutos após a geração da encryption key. Caso seja necessário utilizar\no cartão mais de uma vez faça uma requisição para a rota de cartões e salve esse cartão vinculado ao usuário que o detém,\nassim você receberá um ID único que poderá ser usado para realizar mais transações com o mesmo cartão.\n"
},
"paths": {
"/payment/{id}/write-off": {
"post": {
"summary": "Dar baixa em pagamento",
"tags": [
"Pagamentos"
],
"description": "Marca um pagamento como pago. Utilize esta opção para registrar na NinePay um pagamento que foi feito fora do sistema, como por exemplo, um pagamento em dinheiro ou transferência bancária. Após ser marcado como pago, o cliente não receberá mais cobranças referentes a este pagamento.\n",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"description": "O id do pagamento a ser cancelado",
"schema": {
"type": "integer"
}
}
],
"requestBody": {
"$ref": "#/components/requestBodies/PaymentWriteOffBody"
},
"responses": {
"200": {
"description": "Pagamento baixado com sucesso",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaymentUpdateResponse"
}
}
}
},
"401": {
"$ref": "#/components/responses/401"
},
"422": {
"$ref": "#/components/responses/422"
},
"500": {
"$ref": "#/components/responses/500"
}
}
}
}
},
"components": {
"securitySchemes": {
"Bearer": {
"type": "apiKey",
"in": "header",
"name": "Authorization",
"description": "Todas as requisições que requerem autenticação devem incluir no cabeçalho `Authorization` o token de API enviado pela nossa equipe. O token deve ser fornecido no seguinte formato:\n```\nAuthorization: Bearer \n```"
}
},
"responses": {
"401": {
"description": "Não autenticado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "AUTHENTICATION_ERROR",
"message": "Não autenticado.",
"timestamp": "2026-10-22T12:03:44+00:00",
"request_id": "f2a7e962-6083-4525-816e-f14d4a602e0a",
"documentation_url": "https://docs.ninepay.com.br"
}
}
}
},
"422": {
"description": "Erro na validação dos dados",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "VALIDATION_ERROR",
"message": "Os dados informados são inválidos.",
"errors": {
"email": [
"O campo email é obrigatório."
]
},
"timestamp": "2026-10-22T12:03:54+00:00",
"request_id": "64d62d36-e797-45ed-a9d5-c203bde81032",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Corrija os campos e tente novamente."
}
}
}
},
"500": {
"description": "Erro inesperado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "UNEXPECTED_ERROR",
"message": "Houve um erro inesperado.",
"timestamp": "2026-10-22T12:04:46+00:00",
"request_id": "868443d3-38fd-4c92-8ea8-7cccbbce4308",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Verifique todos os parâmetros da requisição. Se o erro persistir, entre em contato com nossa equipe em ti@ninepay.com.br."
}
}
}
}
},
"schemas": {
"ApiError": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "O código do erro. Ex.: `VALIDATION_ERROR`, `FORBIDDEN_ERROR`, `UNEXPECTED_ERROR`."
},
"message": {
"type": "string",
"description": "A mensagem do erro."
},
"errors": {
"type": "object",
"description": "Os erros de cada campo, quando o `code` é `VALIDATION_ERROR`.",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "A data e hora do erro, em UTC."
},
"request_id": {
"type": "string",
"description": "Um identificador único gerado para esta resposta de erro."
},
"documentation_url": {
"type": "string",
"description": "O endereço desta documentação."
},
"suggestion": {
"type": "string",
"description": "Uma sugestão de como resolver o erro."
}
}
},
"PaymentUpdateResponse": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "O ID do pagamento."
},
"uuid": {
"type": "string",
"description": "O UUID do pagamento."
},
"customer_id": {
"type": "string",
"description": "O ID do cliente do pagamento."
},
"customer": {
"type": "object",
"description": "O cliente do pagamento."
},
"subscription_id": {
"type": "string",
"description": "O ID da assinatura do pagamento."
},
"subscription": {
"type": "object",
"description": "A assinatura do pagamento."
},
"payment_link": {
"type": "object",
"description": "O link de pagamento."
},
"items": {
"type": "array",
"description": "Os itens do pagamento."
},
"allowed_methods": {
"type": "array",
"description": "Os métodos com que o cliente pode pagar este pagamento.",
"items": {
"$ref": "#/components/schemas/PaymentMethods"
}
},
"method": {
"$ref": "#/components/schemas/PaymentResponseMethods"
},
"card_id": {
"type": "string",
"description": "O ID do cartão do pagamento."
},
"card": {
"type": "object",
"description": "O cartão do pagamento."
},
"digitable_line": {
"type": "string",
"description": "A linha digitável do boleto. Só é preenchida para o método `billet`."
},
"pix_payload": {
"type": "string",
"description": "O código Pix copia e cola do pagamento. Só é preenchido para o método `pix`."
},
"custom_data": {
"type": "object",
"description": "Os dados personalizados do pagamento."
},
"value": {
"type": "number",
"description": "O valor original do pagamento em centavos, sem multa e juros. Ex.: 5000 para R$50,00."
},
"fine": {
"type": "number",
"description": "A multa do pagamento, em valor percentual. Ex.: 2 para multa de 2% sobre o valor do pagamento vencido."
},
"interest": {
"type": "number",
"description": "O juros do pagamento, em valor percentual ao mês. Ex.: 2 para 2% ao mês."
},
"current_value": {
"type": "number",
"description": "O valor a ser pago hoje, em centavos: `value` somado a `current_fine` e `current_interest`."
},
"current_fine": {
"type": "number",
"description": "O valor da multa aplicada até hoje, em centavos. É 0 enquanto o pagamento não vence."
},
"current_interest": {
"type": "number",
"description": "O valor dos juros acumulados até hoje, em centavos. É 0 enquanto o pagamento não vence."
},
"installments": {
"type": "number",
"description": "O número de parcelas do pagamento. Só se aplica ao método `credit`."
},
"status": {
"$ref": "#/components/schemas/PaymentStatus"
},
"retries_number": {
"type": "number",
"description": "O número de tentativas do pagamento."
},
"was_last_retry": {
"type": "boolean",
"description": "Se foi a última tentativa do pagamento."
},
"can_refund": {
"type": "boolean",
"description": "Se o pagamento pode ser reembolsado agora. Só é `true` quando o `status` é `paid` e o método é `credit` (até 350 dias após o pagamento) ou `pix` (até 90 dias após o pagamento)."
},
"refunds": {
"type": "array",
"description": "Os reembolsos solicitados para o pagamento. Só é retornado no endpoint de obter detalhes do pagamento quando a requisição inclui `with[]=refunds`.",
"items": {
"$ref": "#/components/schemas/PaymentRefund"
}
},
"receipts": {
"type": "array",
"description": "Os recibos do pagamento."
},
"receipt_status": {
"$ref": "#/components/schemas/ReceiptStatus"
},
"due_date": {
"type": "string",
"format": "date",
"description": "A data de vencimento do pagamento."
},
"ref_date": {
"type": "string",
"format": "date",
"description": "A data de referência do pagamento."
},
"paid_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o pagamento foi pago. É nula enquanto o `status` não é `paid`."
},
"company": {
"type": "object",
"description": "A empresa do pagamento."
},
"charge_enabled": {
"type": "boolean",
"description": "A habilitação da cobrança do pagamento."
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o pagamento foi criado."
},
"updated_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o pagamento foi atualizado."
},
"url": {
"type": "string",
"description": "A URL do pagamento."
},
"receipt_url": {
"type": "string",
"description": "A URL do recibo do pagamento."
}
}
},
"ReceiptStatus": {
"type": "integer",
"enum": [
0,
1,
2,
3,
4
],
"description": "- 0: Emissão de recibo não configurada. - 1: Recibo ainda não emitido. - 2: Recibo emitido. - 3: Erro na emissão do recibo. - 4: Emissão do recibo ignorada.\n"
},
"PaymentRefund": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"description": "O ID do reembolso."
},
"method": {
"type": "string",
"description": "O método do pagamento reembolsado: `credit` ou `pix`."
},
"value": {
"type": "number",
"description": "O valor reembolsado, em centavos."
},
"status": {
"$ref": "#/components/schemas/RefundStatus"
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o reembolso foi solicitado."
},
"updated_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora da última atualização do reembolso."
}
}
},
"RefundStatus": {
"type": "string",
"enum": [
"new",
"processing",
"completed",
"failed"
],
"description": "- new: Reembolso criado, ainda não enviado à adquirente. - processing: Reembolso em processamento na adquirente. - completed: Reembolso concluído; o valor foi devolvido ao cliente. - failed: A adquirente não conseguiu fazer o reembolso.\n"
},
"PaymentStatus": {
"type": "string",
"enum": [
"unpaid",
"paid",
"unauthorized",
"canceled",
"reversed"
],
"description": "- unpaid: Em aberto, aguardando pagamento. - paid: Pago. - unauthorized: Recusado. A tentativa de cobrança no cartão não foi autorizada; o pagamento continua em aberto e pode ser pago novamente. - canceled: Cancelado. - reversed: Estornado.\n"
},
"PaymentResponseMethods": {
"type": "string",
"enum": [
"credit",
"debit",
"billet",
"pix",
"payment_initiation",
"manual"
],
"description": "- credit: Cartão de crédito. - debit: Cartão de débito. - billet: Boleto. - pix: Pix. - payment_initiation: Iniciação de pagamento via Open Finance. - manual: Baixa manual, registrada pelo endpoint de dar baixa em pagamento.\n"
},
"PaymentMethods": {
"type": "string",
"enum": [
"credit",
"billet",
"pix"
]
}
},
"requestBodies": {
"PaymentWriteOffBody": {
"required": false,
"description": "Descreve os dados a serem incluídos no corpo da requisição.\n",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"valueType": {
"type": "string",
"enum": [
"normal",
"zero"
],
"description": "- normal: Mantém o valor do pagamento\n- zero: Zera o valor do pagamento (não será somado aos gráficos de faturamento)\n"
}
}
}
}
}
}
}
},
"tags": [
{
"name": "Pagamentos",
"description": "Pagamentos"
}
],
"x-tagGroups": [
{
"name": "API Calls",
"tags": [
"Pagamentos",
"Clientes",
"Planos",
"Assinaturas",
"Consultas"
]
}
],
"servers": [
{
"url": "https://api.sandbox.cefispay.com.br/api/v1",
"description": "Servidor de Testes (sandbox)"
}
],
"security": [
{
"Bearer": []
}
]
}
```
---
# Reembolsar um pagamento
Source: https://docs.ninepay.com.br/reference/reembolsar-um-pagamento
Solicita o reembolso (estorno) integral de um pagamento já pago. O valor é devolvido ao cliente pelo mesmo meio em que ele pagou.
Um pagamento só pode ser reembolsado quando:
- o `status` é `paid`;
- o `method` é `credit` ou `pix` (boleto e baixa manual não podem ser reembolsados);
- o prazo não expirou: até 350 dias após o pagamento para `credit` e até 90 dias para `pix`;
- não existe outro reembolso deste pagamento em andamento;
- a sua conta tem saldo suficiente para cobrir o valor do pagamento que já foi liberado.
O campo `can_refund` do pagamento indica se ele atende a essas condições, com exceção do saldo e de um reembolso em andamento. Consulte-o antes de chamar este endpoint.
**Resultado:** uma resposta 200 quer dizer que o reembolso foi solicitado à adquirente, não que ele foi concluído. Confira o `status` do pagamento na resposta:
- `reversed`: a adquirente concluiu o reembolso na hora.
- `paid`: o reembolso ficou em processamento ou foi recusado pela adquirente. Para saber qual dos dois, consulte o pagamento no endpoint de obter detalhes do pagamento com `with[]=refunds` e veja o `status` do reembolso mais recente em `refunds`.
Reembolsos em processamento são consultados na adquirente a cada 5 minutos. Quando um deles é concluído, o `status` do pagamento passa a ser `reversed` e o evento de pagamento atualizado é disparado. Um reembolso com `status` `failed` não é tentado de novo; você pode solicitar um novo reembolso por este endpoint.
**Atenção:** quando o pagamento não pode ser reembolsado, a API responde com o status HTTP 500 e o código `UNEXPECTED_ERROR`, sem detalhar o motivo em produção. Verifique as condições acima antes de tentar novamente.
# OpenAPI definition
```json
{
"openapi": "3.0.3",
"info": {
"title": "NinePay API",
"version": "1.0",
"x-logo": {
"url": ""
},
"termsOfService": "https://bit.ly/cefispay-contrato",
"contact": {
"name": "NinePay Engineering Team",
"email": "ti@ninepay.com.br"
},
"description": "# Introdução\nBem vindo a referência da **API NinePay**.\nÉ através desta API que você integra o seu sistema ao nosso.\nNossa API é RESTful, e todas suas respostas são em JSON, no endpoint base:\n```\nhttps://payments.cefis.com.br/api/v1/\n```\n\n## Ambientes\nAlém do ambiente de **produção** temos disponível o ambiente **sandbox**\npara a realização de testes de integração. Toda a comunicação com o ambiente sandbox deve ser feita através da url:\n\n```\nhttps://api.sandbox.cefispay.com.br/api/v1/\n```\n\n## Autenticação\nTodas as requisições que requerem autenticação, deverão informar no header `Authorization` o token de api enviado pela nossa equipe, observando sempre o ambiente desejado e no seguinte formato:\n```\nAuthorization: Bearer \n```\n\n## Headers\nRecomendamos que os cabeçalhos da requisições sejam corretamente adicionados para trabalhar com os tipos de dados enviados e recebidos da API:\n - Todas as requisições devem contem o header `Content-Type: application/json`, a menos que o endpoint específico defina diferente\n - Todas as requisições devem contem o header `Accept: application/json`, a menos que o endpoint específico defina diferente\n\n## Respostas\n- Os recursos vêm dentro de `data`: `GET /customers/{id}` responde `{ \"data\": { ... } }`.\n- As criações respondem **201**. `POST /payments` responde `{ \"customer\", \"payment\", \"invoice_url\" }` (o `invoice_url` só no boleto) e `POST /subscriptions` responde `{ \"customer\", \"subscription\" }`.\n- Valores sempre em centavos (inteiro): R$ 50,00 é `5000`.\n\n## Erros\nTodo erro tem o mesmo formato:\n```json\n{\n \"code\": \"VALIDATION_ERROR\",\n \"message\": \"Os dados informados são inválidos.\",\n \"errors\": { \"email\": [\"O campo email é obrigatório.\"] },\n \"timestamp\": \"2026-10-22T12:03:54+00:00\",\n \"request_id\": \"64d62d36-e797-45ed-a9d5-c203bde81032\",\n \"documentation_url\": \"https://docs.ninepay.com.br\",\n \"suggestion\": \"Corrija os campos e tente novamente.\"\n}\n```\n`errors` só vem na validação, com uma **lista** de mensagens por campo. `suggestion` vem quando há uma. Guarde o `request_id` para falar com o suporte.\n\n| `code` | HTTP | Quando |\n| --- | --- | --- |\n| `AUTHENTICATION_ERROR` | 401 | Token ausente ou inválido |\n| `FORBIDDEN_ERROR` | 403 | O recurso não é da sua empresa. Em várias rotas, um id que não existe também responde 403, para não revelar quais ids existem |\n| `COMPANYBLOCKED_ERROR` | 403 | A conta está suspensa |\n| `RESOURCE_NOT_FOUND_ERROR` | 404 | O recurso não existe |\n| `ROUTE_NOT_FOUND_ERROR` | 404 | A rota não existe |\n| `METHOD_NOT_ALLOWED_ERROR` | 405 | O método não vale para a rota (ex.: `PUT /customers` sem o id) |\n| `INVALID_STATE_ERROR` | 400 | O recurso não está num estado que permita a ação (ex.: cancelar um pagamento já pago) |\n| `VALIDATION_ERROR` | 422 | Dados inválidos; veja `errors` |\n| `REFUND_NOT_ALLOWED` | 422 | O pagamento não pode ser reembolsado |\n| `TOO_MANY_ATTEMPTS` | 429 | Muitas requisições; respeite o cabeçalho `Retry-After` |\n| `UNEXPECTED_ERROR` | 500 | Erro nosso; se repetir, fale com o suporte com o `request_id` |\n\n## Paginação\nAs listagens recebem `page` (a partir de 1) e `limit` (itens por página: **10** por padrão, de 1 a **100**). A resposta traz `data` (os itens), `links` e `meta` (`current_page`, `last_page`, `per_page`, `total`).\n\n## Datas\n- Datas de calendário (`due_date`, `next_payment`) vão como `AAAA-MM-DD` na requisição.\n- Nas respostas, os campos de data e hora aparecem em dois formatos: ISO 8601 em UTC (`2026-10-27T03:00:00.000000Z`, em `due_date` e `ref_date` do pagamento) e `AAAA-MM-DD HH:MM:SS` no horário de Brasília (`created_at` e `updated_at`). Leia o campo pelo formato dele.\n\n## Identificadores\nCada recurso tem um `id` numérico e um `uuid`. Use o `id` nas rotas autenticadas e o **`uuid`** em tudo que é público (o link de pagamento, o checkout e o PDF do boleto).\n\n# Hash de cartões\nO hash de um cartão é uma versão criptografada de todos os dados do cartão do cliente, essa é a maneira mais segura de enviar os dados do cartão\ndo seu cliente diretamente para a gente. Abaixo vamos detalhar como ele funciona e como obter um hash a partir dos dados inseridos pelo cliente.\nÉ importante ressaltar que esse fluxo deve ser executado no front-end, seja ele web ou mobile, e que os dados do cartão do cliente nunca devem\nser enviados para o backend, já o hash do cartão pode ser enviado para o backend sem problemas.\n\n## Gerando uma encryption key\nA encryption key consiste basicamente em uma chave pública RSA usada para encriptar os dados do cartão, essa chave só pode ser usada uma vez, então\nsempre que precisar encriptar um novo cartão você precisa gerar uma nova encryption key.\n\nPara gerar uma encryption key é necessário fazer uma requisição ``POST`` para a rota ``/encryption_keys`` da API enviando como parâmetro seu\n``merchant_id``. Ela não usa o token da API (nunca o coloque no front-end): o ``merchant_id`` identifica a sua conta, e um\n``merchant_id`` que não existe responde 401.\n\nA requisição deverá ter esse formato:\n```\ncurl -X POST https://payments.cefis.com.br/api/v1/encryption_keys -H 'Content-Type: application/json' -d '{\"merchant_id\":\"SEU_MERCHANT_ID\"}'\n```\n\nComo resposta você receberá um objeto JSON no seguinte formato:\n```\n{\n \"id\": 1111,\n \"public_key\": \"-----BEGIN PUBLIC KEY-----\\n ... \\n-----END PUBLIC KEY-----\\n\",\n \"ip_address\": \"000.000.000.000\",\n \"created_at\": \"2017-07-03\",\n}\n```\n\n## Encriptando os dados do cartão\nPara encriptar os dados do cartão primeiro você precisa formatá-los de forma correta, para isso crie uma string JSON\ncontendo todos os dados do cartão no seguinte formato:\n\n```\n{\"card_number\":\"1111111111111111\",\"card_holder_name\":\"Jose Silva\",\"card_expiration_date\":\"11/2021\",\"card_cvv\":\"111\"}\n```\n\nEm seguida faça a criptografia RSA dessa string utilizando a chave pública (public_key) gerada no passo anterior, com\npadding do tipo PKCS1.\n\nApós criptografar os dados converta a string resultante para base64 e você terá um resultado parecido com esse:\n\n```\nGprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nO último passo é concatenar o id da sua encryption key (recebido como resposta da requisição anterior) com a string\nem base64 que representa os dados do cartão, da seguinte forma:\n\n``encryption_key_id + \"_\" + base64_encrypted_card``\n\nO resultado será o seu card hash:\n\n```\n1111_GprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nPronto, agora os dados do cartão do cliente já estão em um formato seguro para serem transportados pela rede, podendo\nagora ser enviados para o seu back-end dar sequência ao fluxo. Vale lembrar que cada card hash pode ser usado apenas\numa vez e além disso tem uma validade máxima de 30 minutos após a geração da encryption key. Caso seja necessário utilizar\no cartão mais de uma vez faça uma requisição para a rota de cartões e salve esse cartão vinculado ao usuário que o detém,\nassim você receberá um ID único que poderá ser usado para realizar mais transações com o mesmo cartão.\n"
},
"paths": {
"/payment/reversal": {
"post": {
"summary": "Reembolsar um pagamento",
"tags": [
"Pagamentos"
],
"description": "Solicita o reembolso (estorno) integral de um pagamento já pago. O valor é devolvido ao cliente pelo mesmo meio em que ele pagou.\n\nUm pagamento só pode ser reembolsado quando:\n- o `status` é `paid`;\n- o `method` é `credit` ou `pix` (boleto e baixa manual não podem ser reembolsados);\n- o prazo não expirou: até 350 dias após o pagamento para `credit` e até 90 dias para `pix`;\n- não existe outro reembolso deste pagamento em andamento;\n- a sua conta tem saldo suficiente para cobrir o valor do pagamento que já foi liberado.\n\nO campo `can_refund` do pagamento indica se ele atende a essas condições, com exceção do saldo e de um reembolso em andamento. Consulte-o antes de chamar este endpoint.\n\n**Resultado:** uma resposta 200 quer dizer que o reembolso foi solicitado à adquirente, não que ele foi concluído. Confira o `status` do pagamento na resposta:\n- `reversed`: a adquirente concluiu o reembolso na hora.\n- `paid`: o reembolso ficou em processamento ou foi recusado pela adquirente. Para saber qual dos dois, consulte o pagamento no endpoint de obter detalhes do pagamento com `with[]=refunds` e veja o `status` do reembolso mais recente em `refunds`.\n\nReembolsos em processamento são consultados na adquirente a cada 5 minutos. Quando um deles é concluído, o `status` do pagamento passa a ser `reversed` e o evento de pagamento atualizado é disparado. Um reembolso com `status` `failed` não é tentado de novo; você pode solicitar um novo reembolso por este endpoint.\n\n**Atenção:** quando o pagamento não pode ser reembolsado, a API responde com o status HTTP 500 e o código `UNEXPECTED_ERROR`, sem detalhar o motivo em produção. Verifique as condições acima antes de tentar novamente.\n",
"requestBody": {
"$ref": "#/components/requestBodies/PaymentReversalBody"
},
"responses": {
"200": {
"description": "Reembolso solicitado com sucesso",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaymentReversalResponse"
}
}
}
},
"401": {
"$ref": "#/components/responses/401"
},
"403": {
"description": "O pagamento não pertence à sua conta",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "FORBIDDEN_ERROR",
"message": "You do not have permission to perform this action.",
"timestamp": "2026-09-28T13:00:00+00:00",
"request_id": "9f3c2a1e-7b4d-4c1a-9e2f-0a1b2c3d4e5f",
"documentation_url": "https://docs.ninepay.com.br"
}
}
}
},
"422": {
"description": "O `payment.id` não foi enviado, não é um número inteiro ou não corresponde a um pagamento existente",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "VALIDATION_ERROR",
"message": "The given data was invalid.",
"errors": {
"payment.id": [
"Payment not found."
]
},
"timestamp": "2026-09-28T13:00:00+00:00",
"request_id": "9f3c2a1e-7b4d-4c1a-9e2f-0a1b2c3d4e5f",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Fix the fields and try again."
}
}
}
},
"500": {
"description": "O pagamento não pode ser reembolsado ou houve um erro inesperado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "UNEXPECTED_ERROR",
"message": "There was an unexpected error.",
"timestamp": "2026-09-28T13:00:00+00:00",
"request_id": "9f3c2a1e-7b4d-4c1a-9e2f-0a1b2c3d4e5f",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Check all request parameters. If the error persists, contact our team in ti@ninepay.com.br."
}
}
}
}
},
"operationId": "refundPayment"
}
}
},
"components": {
"securitySchemes": {
"Bearer": {
"type": "apiKey",
"in": "header",
"name": "Authorization",
"description": "Todas as requisições que requerem autenticação devem incluir no cabeçalho `Authorization` o token de API enviado pela nossa equipe. O token deve ser fornecido no seguinte formato:\n```\nAuthorization: Bearer \n```"
}
},
"schemas": {
"ApiError": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "O código do erro. Ex.: `VALIDATION_ERROR`, `FORBIDDEN_ERROR`, `UNEXPECTED_ERROR`."
},
"message": {
"type": "string",
"description": "A mensagem do erro."
},
"errors": {
"type": "object",
"description": "Os erros de cada campo, quando o `code` é `VALIDATION_ERROR`.",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "A data e hora do erro, em UTC."
},
"request_id": {
"type": "string",
"description": "Um identificador único gerado para esta resposta de erro."
},
"documentation_url": {
"type": "string",
"description": "O endereço desta documentação."
},
"suggestion": {
"type": "string",
"description": "Uma sugestão de como resolver o erro."
}
}
},
"PaymentReversalResponse": {
"type": "object",
"properties": {
"response": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"status": {
"$ref": "#/components/schemas/PaymentStatus"
}
}
},
"payment": {
"$ref": "#/components/schemas/PaymentUpdateResponse"
}
}
}
}
},
"PaymentUpdateResponse": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "O ID do pagamento."
},
"uuid": {
"type": "string",
"description": "O UUID do pagamento."
},
"customer_id": {
"type": "string",
"description": "O ID do cliente do pagamento."
},
"customer": {
"type": "object",
"description": "O cliente do pagamento."
},
"subscription_id": {
"type": "string",
"description": "O ID da assinatura do pagamento."
},
"subscription": {
"type": "object",
"description": "A assinatura do pagamento."
},
"payment_link": {
"type": "object",
"description": "O link de pagamento."
},
"items": {
"type": "array",
"description": "Os itens do pagamento."
},
"allowed_methods": {
"type": "array",
"description": "Os métodos com que o cliente pode pagar este pagamento.",
"items": {
"$ref": "#/components/schemas/PaymentMethods"
}
},
"method": {
"$ref": "#/components/schemas/PaymentResponseMethods"
},
"card_id": {
"type": "string",
"description": "O ID do cartão do pagamento."
},
"card": {
"type": "object",
"description": "O cartão do pagamento."
},
"digitable_line": {
"type": "string",
"description": "A linha digitável do boleto. Só é preenchida para o método `billet`."
},
"pix_payload": {
"type": "string",
"description": "O código Pix copia e cola do pagamento. Só é preenchido para o método `pix`."
},
"custom_data": {
"type": "object",
"description": "Os dados personalizados do pagamento."
},
"value": {
"type": "number",
"description": "O valor original do pagamento em centavos, sem multa e juros. Ex.: 5000 para R$50,00."
},
"fine": {
"type": "number",
"description": "A multa do pagamento, em valor percentual. Ex.: 2 para multa de 2% sobre o valor do pagamento vencido."
},
"interest": {
"type": "number",
"description": "O juros do pagamento, em valor percentual ao mês. Ex.: 2 para 2% ao mês."
},
"current_value": {
"type": "number",
"description": "O valor a ser pago hoje, em centavos: `value` somado a `current_fine` e `current_interest`."
},
"current_fine": {
"type": "number",
"description": "O valor da multa aplicada até hoje, em centavos. É 0 enquanto o pagamento não vence."
},
"current_interest": {
"type": "number",
"description": "O valor dos juros acumulados até hoje, em centavos. É 0 enquanto o pagamento não vence."
},
"installments": {
"type": "number",
"description": "O número de parcelas do pagamento. Só se aplica ao método `credit`."
},
"status": {
"$ref": "#/components/schemas/PaymentStatus"
},
"retries_number": {
"type": "number",
"description": "O número de tentativas do pagamento."
},
"was_last_retry": {
"type": "boolean",
"description": "Se foi a última tentativa do pagamento."
},
"can_refund": {
"type": "boolean",
"description": "Se o pagamento pode ser reembolsado agora. Só é `true` quando o `status` é `paid` e o método é `credit` (até 350 dias após o pagamento) ou `pix` (até 90 dias após o pagamento)."
},
"refunds": {
"type": "array",
"description": "Os reembolsos solicitados para o pagamento. Só é retornado no endpoint de obter detalhes do pagamento quando a requisição inclui `with[]=refunds`.",
"items": {
"$ref": "#/components/schemas/PaymentRefund"
}
},
"receipts": {
"type": "array",
"description": "Os recibos do pagamento."
},
"receipt_status": {
"$ref": "#/components/schemas/ReceiptStatus"
},
"due_date": {
"type": "string",
"format": "date",
"description": "A data de vencimento do pagamento."
},
"ref_date": {
"type": "string",
"format": "date",
"description": "A data de referência do pagamento."
},
"paid_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o pagamento foi pago. É nula enquanto o `status` não é `paid`."
},
"company": {
"type": "object",
"description": "A empresa do pagamento."
},
"charge_enabled": {
"type": "boolean",
"description": "A habilitação da cobrança do pagamento."
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o pagamento foi criado."
},
"updated_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o pagamento foi atualizado."
},
"url": {
"type": "string",
"description": "A URL do pagamento."
},
"receipt_url": {
"type": "string",
"description": "A URL do recibo do pagamento."
}
}
},
"ReceiptStatus": {
"type": "integer",
"enum": [
0,
1,
2,
3,
4
],
"description": "- 0: Emissão de recibo não configurada. - 1: Recibo ainda não emitido. - 2: Recibo emitido. - 3: Erro na emissão do recibo. - 4: Emissão do recibo ignorada.\n"
},
"PaymentRefund": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"description": "O ID do reembolso."
},
"method": {
"type": "string",
"description": "O método do pagamento reembolsado: `credit` ou `pix`."
},
"value": {
"type": "number",
"description": "O valor reembolsado, em centavos."
},
"status": {
"$ref": "#/components/schemas/RefundStatus"
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o reembolso foi solicitado."
},
"updated_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora da última atualização do reembolso."
}
}
},
"RefundStatus": {
"type": "string",
"enum": [
"new",
"processing",
"completed",
"failed"
],
"description": "- new: Reembolso criado, ainda não enviado à adquirente. - processing: Reembolso em processamento na adquirente. - completed: Reembolso concluído; o valor foi devolvido ao cliente. - failed: A adquirente não conseguiu fazer o reembolso.\n"
},
"PaymentStatus": {
"type": "string",
"enum": [
"unpaid",
"paid",
"unauthorized",
"canceled",
"reversed"
],
"description": "- unpaid: Em aberto, aguardando pagamento. - paid: Pago. - unauthorized: Recusado. A tentativa de cobrança no cartão não foi autorizada; o pagamento continua em aberto e pode ser pago novamente. - canceled: Cancelado. - reversed: Estornado.\n"
},
"PaymentResponseMethods": {
"type": "string",
"enum": [
"credit",
"debit",
"billet",
"pix",
"payment_initiation",
"manual"
],
"description": "- credit: Cartão de crédito. - debit: Cartão de débito. - billet: Boleto. - pix: Pix. - payment_initiation: Iniciação de pagamento via Open Finance. - manual: Baixa manual, registrada pelo endpoint de dar baixa em pagamento.\n"
},
"PaymentMethods": {
"type": "string",
"enum": [
"credit",
"billet",
"pix"
]
}
},
"responses": {
"401": {
"description": "Não autenticado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "AUTHENTICATION_ERROR",
"message": "Não autenticado.",
"timestamp": "2026-10-22T12:03:44+00:00",
"request_id": "f2a7e962-6083-4525-816e-f14d4a602e0a",
"documentation_url": "https://docs.ninepay.com.br"
}
}
}
}
},
"requestBodies": {
"PaymentReversalBody": {
"required": true,
"description": "Descreve os dados a serem incluídos no corpo da requisição.\n",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"payment"
],
"properties": {
"payment": {
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "integer",
"description": "O ID do pagamento a ser reembolsado.",
"example": 42
}
}
}
}
}
}
}
}
}
},
"tags": [
{
"name": "Pagamentos",
"description": "Pagamentos"
}
],
"x-tagGroups": [
{
"name": "API Calls",
"tags": [
"Pagamentos",
"Clientes",
"Planos",
"Assinaturas",
"Consultas"
]
}
],
"servers": [
{
"url": "https://api.sandbox.cefispay.com.br/api/v1",
"description": "Servidor de Testes (sandbox)"
}
],
"security": [
{
"Bearer": []
}
]
}
```
---
# Obter PDF do boleto
Source: https://docs.ninepay.com.br/reference/obter-pdf-do-boleto
Retorna o PDF do boleto correspondente ao pagamento especificado pelo UUID especificado. **Atenção:** deve ser o UUID do pagamento, não o ID. Apenas para pagamentos que tenham boleto como método habilitado e ainda não estejam pagos.
# OpenAPI definition
```json
{
"openapi": "3.0.3",
"info": {
"title": "NinePay API",
"version": "1.0",
"x-logo": {
"url": ""
},
"termsOfService": "https://bit.ly/cefispay-contrato",
"contact": {
"name": "NinePay Engineering Team",
"email": "ti@ninepay.com.br"
},
"description": "# Introdução\nBem vindo a referência da **API NinePay**.\nÉ através desta API que você integra o seu sistema ao nosso.\nNossa API é RESTful, e todas suas respostas são em JSON, no endpoint base:\n```\nhttps://payments.cefis.com.br/api/v1/\n```\n\n## Ambientes\nAlém do ambiente de **produção** temos disponível o ambiente **sandbox**\npara a realização de testes de integração. Toda a comunicação com o ambiente sandbox deve ser feita através da url:\n\n```\nhttps://api.sandbox.cefispay.com.br/api/v1/\n```\n\n## Autenticação\nTodas as requisições que requerem autenticação, deverão informar no header `Authorization` o token de api enviado pela nossa equipe, observando sempre o ambiente desejado e no seguinte formato:\n```\nAuthorization: Bearer \n```\n\n## Headers\nRecomendamos que os cabeçalhos da requisições sejam corretamente adicionados para trabalhar com os tipos de dados enviados e recebidos da API:\n - Todas as requisições devem contem o header `Content-Type: application/json`, a menos que o endpoint específico defina diferente\n - Todas as requisições devem contem o header `Accept: application/json`, a menos que o endpoint específico defina diferente\n\n## Respostas\n- Os recursos vêm dentro de `data`: `GET /customers/{id}` responde `{ \"data\": { ... } }`.\n- As criações respondem **201**. `POST /payments` responde `{ \"customer\", \"payment\", \"invoice_url\" }` (o `invoice_url` só no boleto) e `POST /subscriptions` responde `{ \"customer\", \"subscription\" }`.\n- Valores sempre em centavos (inteiro): R$ 50,00 é `5000`.\n\n## Erros\nTodo erro tem o mesmo formato:\n```json\n{\n \"code\": \"VALIDATION_ERROR\",\n \"message\": \"Os dados informados são inválidos.\",\n \"errors\": { \"email\": [\"O campo email é obrigatório.\"] },\n \"timestamp\": \"2026-10-22T12:03:54+00:00\",\n \"request_id\": \"64d62d36-e797-45ed-a9d5-c203bde81032\",\n \"documentation_url\": \"https://docs.ninepay.com.br\",\n \"suggestion\": \"Corrija os campos e tente novamente.\"\n}\n```\n`errors` só vem na validação, com uma **lista** de mensagens por campo. `suggestion` vem quando há uma. Guarde o `request_id` para falar com o suporte.\n\n| `code` | HTTP | Quando |\n| --- | --- | --- |\n| `AUTHENTICATION_ERROR` | 401 | Token ausente ou inválido |\n| `FORBIDDEN_ERROR` | 403 | O recurso não é da sua empresa. Em várias rotas, um id que não existe também responde 403, para não revelar quais ids existem |\n| `COMPANYBLOCKED_ERROR` | 403 | A conta está suspensa |\n| `RESOURCE_NOT_FOUND_ERROR` | 404 | O recurso não existe |\n| `ROUTE_NOT_FOUND_ERROR` | 404 | A rota não existe |\n| `METHOD_NOT_ALLOWED_ERROR` | 405 | O método não vale para a rota (ex.: `PUT /customers` sem o id) |\n| `INVALID_STATE_ERROR` | 400 | O recurso não está num estado que permita a ação (ex.: cancelar um pagamento já pago) |\n| `VALIDATION_ERROR` | 422 | Dados inválidos; veja `errors` |\n| `REFUND_NOT_ALLOWED` | 422 | O pagamento não pode ser reembolsado |\n| `TOO_MANY_ATTEMPTS` | 429 | Muitas requisições; respeite o cabeçalho `Retry-After` |\n| `UNEXPECTED_ERROR` | 500 | Erro nosso; se repetir, fale com o suporte com o `request_id` |\n\n## Paginação\nAs listagens recebem `page` (a partir de 1) e `limit` (itens por página: **10** por padrão, de 1 a **100**). A resposta traz `data` (os itens), `links` e `meta` (`current_page`, `last_page`, `per_page`, `total`).\n\n## Datas\n- Datas de calendário (`due_date`, `next_payment`) vão como `AAAA-MM-DD` na requisição.\n- Nas respostas, os campos de data e hora aparecem em dois formatos: ISO 8601 em UTC (`2026-10-27T03:00:00.000000Z`, em `due_date` e `ref_date` do pagamento) e `AAAA-MM-DD HH:MM:SS` no horário de Brasília (`created_at` e `updated_at`). Leia o campo pelo formato dele.\n\n## Identificadores\nCada recurso tem um `id` numérico e um `uuid`. Use o `id` nas rotas autenticadas e o **`uuid`** em tudo que é público (o link de pagamento, o checkout e o PDF do boleto).\n\n# Hash de cartões\nO hash de um cartão é uma versão criptografada de todos os dados do cartão do cliente, essa é a maneira mais segura de enviar os dados do cartão\ndo seu cliente diretamente para a gente. Abaixo vamos detalhar como ele funciona e como obter um hash a partir dos dados inseridos pelo cliente.\nÉ importante ressaltar que esse fluxo deve ser executado no front-end, seja ele web ou mobile, e que os dados do cartão do cliente nunca devem\nser enviados para o backend, já o hash do cartão pode ser enviado para o backend sem problemas.\n\n## Gerando uma encryption key\nA encryption key consiste basicamente em uma chave pública RSA usada para encriptar os dados do cartão, essa chave só pode ser usada uma vez, então\nsempre que precisar encriptar um novo cartão você precisa gerar uma nova encryption key.\n\nPara gerar uma encryption key é necessário fazer uma requisição ``POST`` para a rota ``/encryption_keys`` da API enviando como parâmetro seu\n``merchant_id``. Ela não usa o token da API (nunca o coloque no front-end): o ``merchant_id`` identifica a sua conta, e um\n``merchant_id`` que não existe responde 401.\n\nA requisição deverá ter esse formato:\n```\ncurl -X POST https://payments.cefis.com.br/api/v1/encryption_keys -H 'Content-Type: application/json' -d '{\"merchant_id\":\"SEU_MERCHANT_ID\"}'\n```\n\nComo resposta você receberá um objeto JSON no seguinte formato:\n```\n{\n \"id\": 1111,\n \"public_key\": \"-----BEGIN PUBLIC KEY-----\\n ... \\n-----END PUBLIC KEY-----\\n\",\n \"ip_address\": \"000.000.000.000\",\n \"created_at\": \"2017-07-03\",\n}\n```\n\n## Encriptando os dados do cartão\nPara encriptar os dados do cartão primeiro você precisa formatá-los de forma correta, para isso crie uma string JSON\ncontendo todos os dados do cartão no seguinte formato:\n\n```\n{\"card_number\":\"1111111111111111\",\"card_holder_name\":\"Jose Silva\",\"card_expiration_date\":\"11/2021\",\"card_cvv\":\"111\"}\n```\n\nEm seguida faça a criptografia RSA dessa string utilizando a chave pública (public_key) gerada no passo anterior, com\npadding do tipo PKCS1.\n\nApós criptografar os dados converta a string resultante para base64 e você terá um resultado parecido com esse:\n\n```\nGprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nO último passo é concatenar o id da sua encryption key (recebido como resposta da requisição anterior) com a string\nem base64 que representa os dados do cartão, da seguinte forma:\n\n``encryption_key_id + \"_\" + base64_encrypted_card``\n\nO resultado será o seu card hash:\n\n```\n1111_GprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nPronto, agora os dados do cartão do cliente já estão em um formato seguro para serem transportados pela rede, podendo\nagora ser enviados para o seu back-end dar sequência ao fluxo. Vale lembrar que cada card hash pode ser usado apenas\numa vez e além disso tem uma validade máxima de 30 minutos após a geração da encryption key. Caso seja necessário utilizar\no cartão mais de uma vez faça uma requisição para a rota de cartões e salve esse cartão vinculado ao usuário que o detém,\nassim você receberá um ID único que poderá ser usado para realizar mais transações com o mesmo cartão.\n"
},
"paths": {
"/payment/{uuid}/invoice": {
"get": {
"summary": "Obter PDF do boleto",
"tags": [
"Pagamentos"
],
"description": "Retorna o PDF do boleto correspondente ao pagamento especificado pelo UUID especificado. **Atenção:** deve ser o UUID do pagamento, não o ID. Apenas para pagamentos que tenham boleto como método habilitado e ainda não estejam pagos.\n",
"security": [],
"parameters": [
{
"name": "uuid",
"in": "path",
"required": true,
"description": "O UUID do pagamento para o qual o boleto será gerado. Para obter o UUID, consulte a documentação de detalhes do pagamento.",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "O boleto em PDF.",
"content": {
"application/pdf": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
},
"404": {
"description": "Pagamento não encontrado"
},
"500": {
"$ref": "#/components/responses/500"
}
}
}
}
},
"components": {
"responses": {
"500": {
"description": "Erro inesperado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "UNEXPECTED_ERROR",
"message": "Houve um erro inesperado.",
"timestamp": "2026-10-22T12:04:46+00:00",
"request_id": "868443d3-38fd-4c92-8ea8-7cccbbce4308",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Verifique todos os parâmetros da requisição. Se o erro persistir, entre em contato com nossa equipe em ti@ninepay.com.br."
}
}
}
}
},
"schemas": {
"ApiError": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "O código do erro. Ex.: `VALIDATION_ERROR`, `FORBIDDEN_ERROR`, `UNEXPECTED_ERROR`."
},
"message": {
"type": "string",
"description": "A mensagem do erro."
},
"errors": {
"type": "object",
"description": "Os erros de cada campo, quando o `code` é `VALIDATION_ERROR`.",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "A data e hora do erro, em UTC."
},
"request_id": {
"type": "string",
"description": "Um identificador único gerado para esta resposta de erro."
},
"documentation_url": {
"type": "string",
"description": "O endereço desta documentação."
},
"suggestion": {
"type": "string",
"description": "Uma sugestão de como resolver o erro."
}
}
}
}
},
"tags": [
{
"name": "Pagamentos",
"description": "Pagamentos"
}
],
"x-tagGroups": [
{
"name": "API Calls",
"tags": [
"Pagamentos",
"Clientes",
"Planos",
"Assinaturas",
"Consultas"
]
}
],
"servers": [
{
"url": "https://api.sandbox.cefispay.com.br/api/v1",
"description": "Servidor de Testes (sandbox)"
}
],
"security": []
}
```
---
# Criar novo cliente
Source: https://docs.ninepay.com.br/reference/criar-novo-cliente
O cliente é uma figura essencial no fluxo de pagamentos, pois representa quem de fato irá realizar um pagamento. Ao criar um cliente na NinePay, um ID único será retornado. Recomendamos vincular este ID aos dados do usuário em seu sistema para evitar a criação de múltiplas contas na NinePay para o mesmo cliente.
**Cartão de crédito:** para cobrar um cliente no cartão, o cadastro dele precisa ter CPF ou CNPJ, telefone, CEP e número do endereço. Esses dados são enviados à adquirente como dados do titular, e a cobrança é recusada se algum deles estiver faltando. Recomendamos cadastrar o cliente com o máximo de informações possível, mesmo que hoje você só cobre por boleto ou Pix.
# OpenAPI definition
```json
{
"openapi": "3.0.3",
"info": {
"title": "NinePay API",
"version": "1.0",
"x-logo": {
"url": ""
},
"termsOfService": "https://bit.ly/cefispay-contrato",
"contact": {
"name": "NinePay Engineering Team",
"email": "ti@ninepay.com.br"
},
"description": "# Introdução\nBem vindo a referência da **API NinePay**.\nÉ através desta API que você integra o seu sistema ao nosso.\nNossa API é RESTful, e todas suas respostas são em JSON, no endpoint base:\n```\nhttps://payments.cefis.com.br/api/v1/\n```\n\n## Ambientes\nAlém do ambiente de **produção** temos disponível o ambiente **sandbox**\npara a realização de testes de integração. Toda a comunicação com o ambiente sandbox deve ser feita através da url:\n\n```\nhttps://api.sandbox.cefispay.com.br/api/v1/\n```\n\n## Autenticação\nTodas as requisições que requerem autenticação, deverão informar no header `Authorization` o token de api enviado pela nossa equipe, observando sempre o ambiente desejado e no seguinte formato:\n```\nAuthorization: Bearer \n```\n\n## Headers\nRecomendamos que os cabeçalhos da requisições sejam corretamente adicionados para trabalhar com os tipos de dados enviados e recebidos da API:\n - Todas as requisições devem contem o header `Content-Type: application/json`, a menos que o endpoint específico defina diferente\n - Todas as requisições devem contem o header `Accept: application/json`, a menos que o endpoint específico defina diferente\n\n## Respostas\n- Os recursos vêm dentro de `data`: `GET /customers/{id}` responde `{ \"data\": { ... } }`.\n- As criações respondem **201**. `POST /payments` responde `{ \"customer\", \"payment\", \"invoice_url\" }` (o `invoice_url` só no boleto) e `POST /subscriptions` responde `{ \"customer\", \"subscription\" }`.\n- Valores sempre em centavos (inteiro): R$ 50,00 é `5000`.\n\n## Erros\nTodo erro tem o mesmo formato:\n```json\n{\n \"code\": \"VALIDATION_ERROR\",\n \"message\": \"Os dados informados são inválidos.\",\n \"errors\": { \"email\": [\"O campo email é obrigatório.\"] },\n \"timestamp\": \"2026-10-22T12:03:54+00:00\",\n \"request_id\": \"64d62d36-e797-45ed-a9d5-c203bde81032\",\n \"documentation_url\": \"https://docs.ninepay.com.br\",\n \"suggestion\": \"Corrija os campos e tente novamente.\"\n}\n```\n`errors` só vem na validação, com uma **lista** de mensagens por campo. `suggestion` vem quando há uma. Guarde o `request_id` para falar com o suporte.\n\n| `code` | HTTP | Quando |\n| --- | --- | --- |\n| `AUTHENTICATION_ERROR` | 401 | Token ausente ou inválido |\n| `FORBIDDEN_ERROR` | 403 | O recurso não é da sua empresa. Em várias rotas, um id que não existe também responde 403, para não revelar quais ids existem |\n| `COMPANYBLOCKED_ERROR` | 403 | A conta está suspensa |\n| `RESOURCE_NOT_FOUND_ERROR` | 404 | O recurso não existe |\n| `ROUTE_NOT_FOUND_ERROR` | 404 | A rota não existe |\n| `METHOD_NOT_ALLOWED_ERROR` | 405 | O método não vale para a rota (ex.: `PUT /customers` sem o id) |\n| `INVALID_STATE_ERROR` | 400 | O recurso não está num estado que permita a ação (ex.: cancelar um pagamento já pago) |\n| `VALIDATION_ERROR` | 422 | Dados inválidos; veja `errors` |\n| `REFUND_NOT_ALLOWED` | 422 | O pagamento não pode ser reembolsado |\n| `TOO_MANY_ATTEMPTS` | 429 | Muitas requisições; respeite o cabeçalho `Retry-After` |\n| `UNEXPECTED_ERROR` | 500 | Erro nosso; se repetir, fale com o suporte com o `request_id` |\n\n## Paginação\nAs listagens recebem `page` (a partir de 1) e `limit` (itens por página: **10** por padrão, de 1 a **100**). A resposta traz `data` (os itens), `links` e `meta` (`current_page`, `last_page`, `per_page`, `total`).\n\n## Datas\n- Datas de calendário (`due_date`, `next_payment`) vão como `AAAA-MM-DD` na requisição.\n- Nas respostas, os campos de data e hora aparecem em dois formatos: ISO 8601 em UTC (`2026-10-27T03:00:00.000000Z`, em `due_date` e `ref_date` do pagamento) e `AAAA-MM-DD HH:MM:SS` no horário de Brasília (`created_at` e `updated_at`). Leia o campo pelo formato dele.\n\n## Identificadores\nCada recurso tem um `id` numérico e um `uuid`. Use o `id` nas rotas autenticadas e o **`uuid`** em tudo que é público (o link de pagamento, o checkout e o PDF do boleto).\n\n# Hash de cartões\nO hash de um cartão é uma versão criptografada de todos os dados do cartão do cliente, essa é a maneira mais segura de enviar os dados do cartão\ndo seu cliente diretamente para a gente. Abaixo vamos detalhar como ele funciona e como obter um hash a partir dos dados inseridos pelo cliente.\nÉ importante ressaltar que esse fluxo deve ser executado no front-end, seja ele web ou mobile, e que os dados do cartão do cliente nunca devem\nser enviados para o backend, já o hash do cartão pode ser enviado para o backend sem problemas.\n\n## Gerando uma encryption key\nA encryption key consiste basicamente em uma chave pública RSA usada para encriptar os dados do cartão, essa chave só pode ser usada uma vez, então\nsempre que precisar encriptar um novo cartão você precisa gerar uma nova encryption key.\n\nPara gerar uma encryption key é necessário fazer uma requisição ``POST`` para a rota ``/encryption_keys`` da API enviando como parâmetro seu\n``merchant_id``. Ela não usa o token da API (nunca o coloque no front-end): o ``merchant_id`` identifica a sua conta, e um\n``merchant_id`` que não existe responde 401.\n\nA requisição deverá ter esse formato:\n```\ncurl -X POST https://payments.cefis.com.br/api/v1/encryption_keys -H 'Content-Type: application/json' -d '{\"merchant_id\":\"SEU_MERCHANT_ID\"}'\n```\n\nComo resposta você receberá um objeto JSON no seguinte formato:\n```\n{\n \"id\": 1111,\n \"public_key\": \"-----BEGIN PUBLIC KEY-----\\n ... \\n-----END PUBLIC KEY-----\\n\",\n \"ip_address\": \"000.000.000.000\",\n \"created_at\": \"2017-07-03\",\n}\n```\n\n## Encriptando os dados do cartão\nPara encriptar os dados do cartão primeiro você precisa formatá-los de forma correta, para isso crie uma string JSON\ncontendo todos os dados do cartão no seguinte formato:\n\n```\n{\"card_number\":\"1111111111111111\",\"card_holder_name\":\"Jose Silva\",\"card_expiration_date\":\"11/2021\",\"card_cvv\":\"111\"}\n```\n\nEm seguida faça a criptografia RSA dessa string utilizando a chave pública (public_key) gerada no passo anterior, com\npadding do tipo PKCS1.\n\nApós criptografar os dados converta a string resultante para base64 e você terá um resultado parecido com esse:\n\n```\nGprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nO último passo é concatenar o id da sua encryption key (recebido como resposta da requisição anterior) com a string\nem base64 que representa os dados do cartão, da seguinte forma:\n\n``encryption_key_id + \"_\" + base64_encrypted_card``\n\nO resultado será o seu card hash:\n\n```\n1111_GprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nPronto, agora os dados do cartão do cliente já estão em um formato seguro para serem transportados pela rede, podendo\nagora ser enviados para o seu back-end dar sequência ao fluxo. Vale lembrar que cada card hash pode ser usado apenas\numa vez e além disso tem uma validade máxima de 30 minutos após a geração da encryption key. Caso seja necessário utilizar\no cartão mais de uma vez faça uma requisição para a rota de cartões e salve esse cartão vinculado ao usuário que o detém,\nassim você receberá um ID único que poderá ser usado para realizar mais transações com o mesmo cartão.\n"
},
"paths": {
"/customers": {
"post": {
"summary": "Criar novo cliente",
"tags": [
"Clientes"
],
"description": "O cliente é uma figura essencial no fluxo de pagamentos, pois representa quem de fato irá realizar um pagamento. Ao criar um cliente na NinePay, um ID único será retornado. Recomendamos vincular este ID aos dados do usuário em seu sistema para evitar a criação de múltiplas contas na NinePay para o mesmo cliente.\n**Cartão de crédito:** para cobrar um cliente no cartão, o cadastro dele precisa ter CPF ou CNPJ, telefone, CEP e número do endereço. Esses dados são enviados à adquirente como dados do titular, e a cobrança é recusada se algum deles estiver faltando. Recomendamos cadastrar o cliente com o máximo de informações possível, mesmo que hoje você só cobre por boleto ou Pix.\n",
"requestBody": {
"$ref": "#/components/requestBodies/CustomerBody"
},
"responses": {
"200": {
"description": "Cliente criado com sucesso",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Customer"
}
}
}
},
"401": {
"$ref": "#/components/responses/401"
},
"422": {
"$ref": "#/components/responses/422"
},
"500": {
"$ref": "#/components/responses/500"
}
},
"operationId": "createCustomer"
}
}
},
"components": {
"securitySchemes": {
"Bearer": {
"type": "apiKey",
"in": "header",
"name": "Authorization",
"description": "Todas as requisições que requerem autenticação devem incluir no cabeçalho `Authorization` o token de API enviado pela nossa equipe. O token deve ser fornecido no seguinte formato:\n```\nAuthorization: Bearer \n```"
}
},
"responses": {
"401": {
"description": "Não autenticado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "AUTHENTICATION_ERROR",
"message": "Não autenticado.",
"timestamp": "2026-10-22T12:03:44+00:00",
"request_id": "f2a7e962-6083-4525-816e-f14d4a602e0a",
"documentation_url": "https://docs.ninepay.com.br"
}
}
}
},
"422": {
"description": "Erro na validação dos dados",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "VALIDATION_ERROR",
"message": "Os dados informados são inválidos.",
"errors": {
"email": [
"O campo email é obrigatório."
]
},
"timestamp": "2026-10-22T12:03:54+00:00",
"request_id": "64d62d36-e797-45ed-a9d5-c203bde81032",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Corrija os campos e tente novamente."
}
}
}
},
"500": {
"description": "Erro inesperado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "UNEXPECTED_ERROR",
"message": "Houve um erro inesperado.",
"timestamp": "2026-10-22T12:04:46+00:00",
"request_id": "868443d3-38fd-4c92-8ea8-7cccbbce4308",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Verifique todos os parâmetros da requisição. Se o erro persistir, entre em contato com nossa equipe em ti@ninepay.com.br."
}
}
}
}
},
"schemas": {
"ApiError": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "O código do erro. Ex.: `VALIDATION_ERROR`, `FORBIDDEN_ERROR`, `UNEXPECTED_ERROR`."
},
"message": {
"type": "string",
"description": "A mensagem do erro."
},
"errors": {
"type": "object",
"description": "Os erros de cada campo, quando o `code` é `VALIDATION_ERROR`.",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "A data e hora do erro, em UTC."
},
"request_id": {
"type": "string",
"description": "Um identificador único gerado para esta resposta de erro."
},
"documentation_url": {
"type": "string",
"description": "O endereço desta documentação."
},
"suggestion": {
"type": "string",
"description": "Uma sugestão de como resolver o erro."
}
}
},
"Customer": {
"type": "object",
"required": [
"id",
"name",
"email",
"cpf",
"cnpj"
],
"properties": {
"id": {
"description": "O id do cliente na NinePay. Obrigatório se os demais dados do usuário não forem informados",
"type": "integer",
"example": 42,
"readOnly": true
},
"name": {
"description": "O nome do cliente. Obrigatório se o `id` não for informado",
"type": "string",
"example": "Jhon Doe"
},
"email": {
"description": "O email do cliente. Obrigatório se o `id` não for informado",
"type": "string",
"example": "jhon@doe.com"
},
"cpf": {
"description": "O cpf do cliente. Obrigatório se o `id` ou o `cnpj` não forem informados",
"type": "string",
"example": "833.828.600-15"
},
"cnpj": {
"description": "O cnpj do cliente. Obrigatório se o `id` ou o `cpf` não forem informados",
"type": "string",
"example": "95.135.209/0001-79"
},
"phone": {
"description": "O telefone celular do cliente, com DDD. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": "(11) 11111-1111"
},
"cep": {
"description": "O CEP do cliente. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": "01423-910"
},
"address": {
"description": "O endereço do cliente",
"type": "string",
"example": "Rua José Maria Lisboa"
},
"number": {
"description": "O número do endereço do cliente. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": 42
},
"district": {
"description": "O bairro do cliente",
"type": "string",
"example": "Jardim Paulista"
},
"city": {
"description": "A cidade do cliente",
"type": "string",
"example": "São Paulo"
},
"state": {
"description": "O estado do cliente",
"type": "string",
"example": "SP"
},
"country": {
"description": "O código do país do cliente, no formato Alpha 2 de acordo com a [ISO 3166](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes).",
"type": "string",
"example": "BR"
}
}
},
"CustomerBody": {
"type": "object",
"required": [
"name",
"email"
],
"properties": {
"name": {
"description": "O nome do cliente.",
"type": "string"
},
"email": {
"description": "O email do cliente.",
"type": "string"
},
"cpf": {
"description": "O CPF do cliente, se pessoa física. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": "13690958725"
},
"cnpj": {
"description": "O CNPJ do cliente, se pessoa jurídica. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": "32614517000167"
},
"phone": {
"description": "O telefone celular do cliente, com DDD. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": "(11) 95665-6556"
},
"cep": {
"description": "O CEP do cliente. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": "01001-010"
},
"address": {
"description": "O endereço do cliente.",
"type": "string"
},
"number": {
"description": "O número do endereço do cliente. Obrigatório para cobranças no cartão de crédito.",
"type": "string"
},
"complement": {
"description": "O complemento do endereço do cliente.",
"type": "string"
},
"district": {
"description": "O bairro do cliente.",
"type": "string"
},
"city": {
"description": "A cidade do cliente.",
"type": "string"
},
"state": {
"description": "A sigla do estado do cliente.",
"type": "string",
"example": "SP"
},
"country": {
"description": "A sigla do país do cliente.",
"type": "string",
"example": "BR"
},
"status": {
"description": "O status do cliente. `1 = Ativo` `2 = Inativo`\n",
"$ref": "#/components/schemas/CustomerStatus",
"example": 1
}
}
},
"CustomerStatus": {
"type": "integer",
"enum": [
1,
2
],
"description": "- 1: Ativo - 2: Inativo\n"
}
},
"requestBodies": {
"CustomerBody": {
"required": true,
"description": "Descreve os dados a serem incluídos no corpo da requisição.\n",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CustomerBody"
}
}
}
}
}
},
"tags": [
{
"name": "Clientes",
"description": "Clientes"
}
],
"x-tagGroups": [
{
"name": "API Calls",
"tags": [
"Pagamentos",
"Clientes",
"Planos",
"Assinaturas",
"Consultas"
]
}
],
"servers": [
{
"url": "https://api.sandbox.cefispay.com.br/api/v1",
"description": "Servidor de Testes (sandbox)"
}
],
"security": [
{
"Bearer": []
}
]
}
```
---
# Atualizar cliente existente
Source: https://docs.ninepay.com.br/reference/atualizar-cliente-existente
Atualiza um cliente existente com base no ID fornecido. **Nota:** É necessário fornecer o ID do cliente que deseja atualizar.
# OpenAPI definition
```json
{
"openapi": "3.0.3",
"info": {
"title": "NinePay API",
"version": "1.0",
"x-logo": {
"url": ""
},
"termsOfService": "https://bit.ly/cefispay-contrato",
"contact": {
"name": "NinePay Engineering Team",
"email": "ti@ninepay.com.br"
},
"description": "# Introdução\nBem vindo a referência da **API NinePay**.\nÉ através desta API que você integra o seu sistema ao nosso.\nNossa API é RESTful, e todas suas respostas são em JSON, no endpoint base:\n```\nhttps://payments.cefis.com.br/api/v1/\n```\n\n## Ambientes\nAlém do ambiente de **produção** temos disponível o ambiente **sandbox**\npara a realização de testes de integração. Toda a comunicação com o ambiente sandbox deve ser feita através da url:\n\n```\nhttps://api.sandbox.cefispay.com.br/api/v1/\n```\n\n## Autenticação\nTodas as requisições que requerem autenticação, deverão informar no header `Authorization` o token de api enviado pela nossa equipe, observando sempre o ambiente desejado e no seguinte formato:\n```\nAuthorization: Bearer \n```\n\n## Headers\nRecomendamos que os cabeçalhos da requisições sejam corretamente adicionados para trabalhar com os tipos de dados enviados e recebidos da API:\n - Todas as requisições devem contem o header `Content-Type: application/json`, a menos que o endpoint específico defina diferente\n - Todas as requisições devem contem o header `Accept: application/json`, a menos que o endpoint específico defina diferente\n\n## Respostas\n- Os recursos vêm dentro de `data`: `GET /customers/{id}` responde `{ \"data\": { ... } }`.\n- As criações respondem **201**. `POST /payments` responde `{ \"customer\", \"payment\", \"invoice_url\" }` (o `invoice_url` só no boleto) e `POST /subscriptions` responde `{ \"customer\", \"subscription\" }`.\n- Valores sempre em centavos (inteiro): R$ 50,00 é `5000`.\n\n## Erros\nTodo erro tem o mesmo formato:\n```json\n{\n \"code\": \"VALIDATION_ERROR\",\n \"message\": \"Os dados informados são inválidos.\",\n \"errors\": { \"email\": [\"O campo email é obrigatório.\"] },\n \"timestamp\": \"2026-10-22T12:03:54+00:00\",\n \"request_id\": \"64d62d36-e797-45ed-a9d5-c203bde81032\",\n \"documentation_url\": \"https://docs.ninepay.com.br\",\n \"suggestion\": \"Corrija os campos e tente novamente.\"\n}\n```\n`errors` só vem na validação, com uma **lista** de mensagens por campo. `suggestion` vem quando há uma. Guarde o `request_id` para falar com o suporte.\n\n| `code` | HTTP | Quando |\n| --- | --- | --- |\n| `AUTHENTICATION_ERROR` | 401 | Token ausente ou inválido |\n| `FORBIDDEN_ERROR` | 403 | O recurso não é da sua empresa. Em várias rotas, um id que não existe também responde 403, para não revelar quais ids existem |\n| `COMPANYBLOCKED_ERROR` | 403 | A conta está suspensa |\n| `RESOURCE_NOT_FOUND_ERROR` | 404 | O recurso não existe |\n| `ROUTE_NOT_FOUND_ERROR` | 404 | A rota não existe |\n| `METHOD_NOT_ALLOWED_ERROR` | 405 | O método não vale para a rota (ex.: `PUT /customers` sem o id) |\n| `INVALID_STATE_ERROR` | 400 | O recurso não está num estado que permita a ação (ex.: cancelar um pagamento já pago) |\n| `VALIDATION_ERROR` | 422 | Dados inválidos; veja `errors` |\n| `REFUND_NOT_ALLOWED` | 422 | O pagamento não pode ser reembolsado |\n| `TOO_MANY_ATTEMPTS` | 429 | Muitas requisições; respeite o cabeçalho `Retry-After` |\n| `UNEXPECTED_ERROR` | 500 | Erro nosso; se repetir, fale com o suporte com o `request_id` |\n\n## Paginação\nAs listagens recebem `page` (a partir de 1) e `limit` (itens por página: **10** por padrão, de 1 a **100**). A resposta traz `data` (os itens), `links` e `meta` (`current_page`, `last_page`, `per_page`, `total`).\n\n## Datas\n- Datas de calendário (`due_date`, `next_payment`) vão como `AAAA-MM-DD` na requisição.\n- Nas respostas, os campos de data e hora aparecem em dois formatos: ISO 8601 em UTC (`2026-10-27T03:00:00.000000Z`, em `due_date` e `ref_date` do pagamento) e `AAAA-MM-DD HH:MM:SS` no horário de Brasília (`created_at` e `updated_at`). Leia o campo pelo formato dele.\n\n## Identificadores\nCada recurso tem um `id` numérico e um `uuid`. Use o `id` nas rotas autenticadas e o **`uuid`** em tudo que é público (o link de pagamento, o checkout e o PDF do boleto).\n\n# Hash de cartões\nO hash de um cartão é uma versão criptografada de todos os dados do cartão do cliente, essa é a maneira mais segura de enviar os dados do cartão\ndo seu cliente diretamente para a gente. Abaixo vamos detalhar como ele funciona e como obter um hash a partir dos dados inseridos pelo cliente.\nÉ importante ressaltar que esse fluxo deve ser executado no front-end, seja ele web ou mobile, e que os dados do cartão do cliente nunca devem\nser enviados para o backend, já o hash do cartão pode ser enviado para o backend sem problemas.\n\n## Gerando uma encryption key\nA encryption key consiste basicamente em uma chave pública RSA usada para encriptar os dados do cartão, essa chave só pode ser usada uma vez, então\nsempre que precisar encriptar um novo cartão você precisa gerar uma nova encryption key.\n\nPara gerar uma encryption key é necessário fazer uma requisição ``POST`` para a rota ``/encryption_keys`` da API enviando como parâmetro seu\n``merchant_id``. Ela não usa o token da API (nunca o coloque no front-end): o ``merchant_id`` identifica a sua conta, e um\n``merchant_id`` que não existe responde 401.\n\nA requisição deverá ter esse formato:\n```\ncurl -X POST https://payments.cefis.com.br/api/v1/encryption_keys -H 'Content-Type: application/json' -d '{\"merchant_id\":\"SEU_MERCHANT_ID\"}'\n```\n\nComo resposta você receberá um objeto JSON no seguinte formato:\n```\n{\n \"id\": 1111,\n \"public_key\": \"-----BEGIN PUBLIC KEY-----\\n ... \\n-----END PUBLIC KEY-----\\n\",\n \"ip_address\": \"000.000.000.000\",\n \"created_at\": \"2017-07-03\",\n}\n```\n\n## Encriptando os dados do cartão\nPara encriptar os dados do cartão primeiro você precisa formatá-los de forma correta, para isso crie uma string JSON\ncontendo todos os dados do cartão no seguinte formato:\n\n```\n{\"card_number\":\"1111111111111111\",\"card_holder_name\":\"Jose Silva\",\"card_expiration_date\":\"11/2021\",\"card_cvv\":\"111\"}\n```\n\nEm seguida faça a criptografia RSA dessa string utilizando a chave pública (public_key) gerada no passo anterior, com\npadding do tipo PKCS1.\n\nApós criptografar os dados converta a string resultante para base64 e você terá um resultado parecido com esse:\n\n```\nGprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nO último passo é concatenar o id da sua encryption key (recebido como resposta da requisição anterior) com a string\nem base64 que representa os dados do cartão, da seguinte forma:\n\n``encryption_key_id + \"_\" + base64_encrypted_card``\n\nO resultado será o seu card hash:\n\n```\n1111_GprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nPronto, agora os dados do cartão do cliente já estão em um formato seguro para serem transportados pela rede, podendo\nagora ser enviados para o seu back-end dar sequência ao fluxo. Vale lembrar que cada card hash pode ser usado apenas\numa vez e além disso tem uma validade máxima de 30 minutos após a geração da encryption key. Caso seja necessário utilizar\no cartão mais de uma vez faça uma requisição para a rota de cartões e salve esse cartão vinculado ao usuário que o detém,\nassim você receberá um ID único que poderá ser usado para realizar mais transações com o mesmo cartão.\n"
},
"paths": {
"/customers": {
"put": {
"summary": "Atualizar cliente existente",
"tags": [
"Clientes"
],
"description": "Atualiza um cliente existente com base no ID fornecido. **Nota:** É necessário fornecer o ID do cliente que deseja atualizar.\n",
"requestBody": {
"$ref": "#/components/requestBodies/CustomerBody"
},
"responses": {
"200": {
"description": "Cliente atualizado com sucesso",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CustomerUpdateResponse"
}
}
}
},
"401": {
"$ref": "#/components/responses/401"
},
"422": {
"$ref": "#/components/responses/422"
},
"500": {
"$ref": "#/components/responses/500"
}
}
}
}
},
"components": {
"securitySchemes": {
"Bearer": {
"type": "apiKey",
"in": "header",
"name": "Authorization",
"description": "Todas as requisições que requerem autenticação devem incluir no cabeçalho `Authorization` o token de API enviado pela nossa equipe. O token deve ser fornecido no seguinte formato:\n```\nAuthorization: Bearer \n```"
}
},
"responses": {
"401": {
"description": "Não autenticado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "AUTHENTICATION_ERROR",
"message": "Não autenticado.",
"timestamp": "2026-10-22T12:03:44+00:00",
"request_id": "f2a7e962-6083-4525-816e-f14d4a602e0a",
"documentation_url": "https://docs.ninepay.com.br"
}
}
}
},
"422": {
"description": "Erro na validação dos dados",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "VALIDATION_ERROR",
"message": "Os dados informados são inválidos.",
"errors": {
"email": [
"O campo email é obrigatório."
]
},
"timestamp": "2026-10-22T12:03:54+00:00",
"request_id": "64d62d36-e797-45ed-a9d5-c203bde81032",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Corrija os campos e tente novamente."
}
}
}
},
"500": {
"description": "Erro inesperado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "UNEXPECTED_ERROR",
"message": "Houve um erro inesperado.",
"timestamp": "2026-10-22T12:04:46+00:00",
"request_id": "868443d3-38fd-4c92-8ea8-7cccbbce4308",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Verifique todos os parâmetros da requisição. Se o erro persistir, entre em contato com nossa equipe em ti@ninepay.com.br."
}
}
}
}
},
"schemas": {
"ApiError": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "O código do erro. Ex.: `VALIDATION_ERROR`, `FORBIDDEN_ERROR`, `UNEXPECTED_ERROR`."
},
"message": {
"type": "string",
"description": "A mensagem do erro."
},
"errors": {
"type": "object",
"description": "Os erros de cada campo, quando o `code` é `VALIDATION_ERROR`.",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "A data e hora do erro, em UTC."
},
"request_id": {
"type": "string",
"description": "Um identificador único gerado para esta resposta de erro."
},
"documentation_url": {
"type": "string",
"description": "O endereço desta documentação."
},
"suggestion": {
"type": "string",
"description": "Uma sugestão de como resolver o erro."
}
}
},
"CustomerUpdateResponse": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "O ID do cliente."
},
"name": {
"type": "string",
"description": "O nome do cliente."
},
"email": {
"type": "string",
"description": "O email do cliente."
},
"cc_emails": {
"type": "string",
"description": "Os emails CC do cliente."
},
"cpf": {
"type": "string",
"description": "O CPF do cliente se pessoa física."
},
"cnpj": {
"type": "string",
"description": "O CNPJ do cliente se pessoa jurídica."
},
"phone": {
"type": "string",
"description": "O telefone do cliente."
},
"cep": {
"type": "string",
"description": "O CEP do cliente."
},
"address": {
"type": "string",
"description": "O endereço do cliente."
},
"number": {
"type": "string",
"description": "O número do endereço do cliente."
},
"complement": {
"type": "string",
"description": "O complemento do endereço do cliente."
},
"district": {
"type": "string",
"description": "O bairro do cliente."
},
"city": {
"type": "string",
"description": "A cidade do cliente."
},
"state": {
"type": "string",
"description": "A sigla do estado do cliente."
},
"country": {
"type": "string",
"description": "A sigla do país do cliente."
},
"state_enrollment": {
"type": "string",
"description": "A inscrição estadual do cliente."
},
"city_enrollment": {
"type": "string",
"description": "A inscrição municipal do cliente."
},
"tax_regime": {
"type": "string",
"description": "O regime tributário do cliente."
},
"special_tax_regime": {
"type": "string",
"description": "O regime tributário especial do cliente."
},
"icms_taxpayer": {
"type": "string",
"description": "O contribuinte do ICMS do cliente."
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o cliente foi criado."
},
"updated_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o cliente foi atualizado."
},
"receipt_config": {
"type": "object",
"description": "A configuração do recibo do cliente."
}
}
},
"CustomerBody": {
"type": "object",
"required": [
"name",
"email"
],
"properties": {
"name": {
"description": "O nome do cliente.",
"type": "string"
},
"email": {
"description": "O email do cliente.",
"type": "string"
},
"cpf": {
"description": "O CPF do cliente, se pessoa física. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": "13690958725"
},
"cnpj": {
"description": "O CNPJ do cliente, se pessoa jurídica. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": "32614517000167"
},
"phone": {
"description": "O telefone celular do cliente, com DDD. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": "(11) 95665-6556"
},
"cep": {
"description": "O CEP do cliente. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": "01001-010"
},
"address": {
"description": "O endereço do cliente.",
"type": "string"
},
"number": {
"description": "O número do endereço do cliente. Obrigatório para cobranças no cartão de crédito.",
"type": "string"
},
"complement": {
"description": "O complemento do endereço do cliente.",
"type": "string"
},
"district": {
"description": "O bairro do cliente.",
"type": "string"
},
"city": {
"description": "A cidade do cliente.",
"type": "string"
},
"state": {
"description": "A sigla do estado do cliente.",
"type": "string",
"example": "SP"
},
"country": {
"description": "A sigla do país do cliente.",
"type": "string",
"example": "BR"
},
"status": {
"description": "O status do cliente. `1 = Ativo` `2 = Inativo`\n",
"$ref": "#/components/schemas/CustomerStatus",
"example": 1
}
}
},
"CustomerStatus": {
"type": "integer",
"enum": [
1,
2
],
"description": "- 1: Ativo - 2: Inativo\n"
}
},
"requestBodies": {
"CustomerBody": {
"required": true,
"description": "Descreve os dados a serem incluídos no corpo da requisição.\n",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CustomerBody"
}
}
}
}
}
},
"tags": [
{
"name": "Clientes",
"description": "Clientes"
}
],
"x-tagGroups": [
{
"name": "API Calls",
"tags": [
"Pagamentos",
"Clientes",
"Planos",
"Assinaturas",
"Consultas"
]
}
],
"servers": [
{
"url": "https://api.sandbox.cefispay.com.br/api/v1",
"description": "Servidor de Testes (sandbox)"
}
],
"security": [
{
"Bearer": []
}
]
}
```
---
# Obter detalhes do cliente
Source: https://docs.ninepay.com.br/reference/obter-detalhes-do-cliente
Retorna os detalhes de um cliente específico, com base no ID fornecido. **Nota:** É necessário fornecer o ID do cliente para obter os detalhes.
# OpenAPI definition
```json
{
"openapi": "3.0.3",
"info": {
"title": "NinePay API",
"version": "1.0",
"x-logo": {
"url": ""
},
"termsOfService": "https://bit.ly/cefispay-contrato",
"contact": {
"name": "NinePay Engineering Team",
"email": "ti@ninepay.com.br"
},
"description": "# Introdução\nBem vindo a referência da **API NinePay**.\nÉ através desta API que você integra o seu sistema ao nosso.\nNossa API é RESTful, e todas suas respostas são em JSON, no endpoint base:\n```\nhttps://payments.cefis.com.br/api/v1/\n```\n\n## Ambientes\nAlém do ambiente de **produção** temos disponível o ambiente **sandbox**\npara a realização de testes de integração. Toda a comunicação com o ambiente sandbox deve ser feita através da url:\n\n```\nhttps://api.sandbox.cefispay.com.br/api/v1/\n```\n\n## Autenticação\nTodas as requisições que requerem autenticação, deverão informar no header `Authorization` o token de api enviado pela nossa equipe, observando sempre o ambiente desejado e no seguinte formato:\n```\nAuthorization: Bearer \n```\n\n## Headers\nRecomendamos que os cabeçalhos da requisições sejam corretamente adicionados para trabalhar com os tipos de dados enviados e recebidos da API:\n - Todas as requisições devem contem o header `Content-Type: application/json`, a menos que o endpoint específico defina diferente\n - Todas as requisições devem contem o header `Accept: application/json`, a menos que o endpoint específico defina diferente\n\n## Respostas\n- Os recursos vêm dentro de `data`: `GET /customers/{id}` responde `{ \"data\": { ... } }`.\n- As criações respondem **201**. `POST /payments` responde `{ \"customer\", \"payment\", \"invoice_url\" }` (o `invoice_url` só no boleto) e `POST /subscriptions` responde `{ \"customer\", \"subscription\" }`.\n- Valores sempre em centavos (inteiro): R$ 50,00 é `5000`.\n\n## Erros\nTodo erro tem o mesmo formato:\n```json\n{\n \"code\": \"VALIDATION_ERROR\",\n \"message\": \"Os dados informados são inválidos.\",\n \"errors\": { \"email\": [\"O campo email é obrigatório.\"] },\n \"timestamp\": \"2026-10-22T12:03:54+00:00\",\n \"request_id\": \"64d62d36-e797-45ed-a9d5-c203bde81032\",\n \"documentation_url\": \"https://docs.ninepay.com.br\",\n \"suggestion\": \"Corrija os campos e tente novamente.\"\n}\n```\n`errors` só vem na validação, com uma **lista** de mensagens por campo. `suggestion` vem quando há uma. Guarde o `request_id` para falar com o suporte.\n\n| `code` | HTTP | Quando |\n| --- | --- | --- |\n| `AUTHENTICATION_ERROR` | 401 | Token ausente ou inválido |\n| `FORBIDDEN_ERROR` | 403 | O recurso não é da sua empresa. Em várias rotas, um id que não existe também responde 403, para não revelar quais ids existem |\n| `COMPANYBLOCKED_ERROR` | 403 | A conta está suspensa |\n| `RESOURCE_NOT_FOUND_ERROR` | 404 | O recurso não existe |\n| `ROUTE_NOT_FOUND_ERROR` | 404 | A rota não existe |\n| `METHOD_NOT_ALLOWED_ERROR` | 405 | O método não vale para a rota (ex.: `PUT /customers` sem o id) |\n| `INVALID_STATE_ERROR` | 400 | O recurso não está num estado que permita a ação (ex.: cancelar um pagamento já pago) |\n| `VALIDATION_ERROR` | 422 | Dados inválidos; veja `errors` |\n| `REFUND_NOT_ALLOWED` | 422 | O pagamento não pode ser reembolsado |\n| `TOO_MANY_ATTEMPTS` | 429 | Muitas requisições; respeite o cabeçalho `Retry-After` |\n| `UNEXPECTED_ERROR` | 500 | Erro nosso; se repetir, fale com o suporte com o `request_id` |\n\n## Paginação\nAs listagens recebem `page` (a partir de 1) e `limit` (itens por página: **10** por padrão, de 1 a **100**). A resposta traz `data` (os itens), `links` e `meta` (`current_page`, `last_page`, `per_page`, `total`).\n\n## Datas\n- Datas de calendário (`due_date`, `next_payment`) vão como `AAAA-MM-DD` na requisição.\n- Nas respostas, os campos de data e hora aparecem em dois formatos: ISO 8601 em UTC (`2026-10-27T03:00:00.000000Z`, em `due_date` e `ref_date` do pagamento) e `AAAA-MM-DD HH:MM:SS` no horário de Brasília (`created_at` e `updated_at`). Leia o campo pelo formato dele.\n\n## Identificadores\nCada recurso tem um `id` numérico e um `uuid`. Use o `id` nas rotas autenticadas e o **`uuid`** em tudo que é público (o link de pagamento, o checkout e o PDF do boleto).\n\n# Hash de cartões\nO hash de um cartão é uma versão criptografada de todos os dados do cartão do cliente, essa é a maneira mais segura de enviar os dados do cartão\ndo seu cliente diretamente para a gente. Abaixo vamos detalhar como ele funciona e como obter um hash a partir dos dados inseridos pelo cliente.\nÉ importante ressaltar que esse fluxo deve ser executado no front-end, seja ele web ou mobile, e que os dados do cartão do cliente nunca devem\nser enviados para o backend, já o hash do cartão pode ser enviado para o backend sem problemas.\n\n## Gerando uma encryption key\nA encryption key consiste basicamente em uma chave pública RSA usada para encriptar os dados do cartão, essa chave só pode ser usada uma vez, então\nsempre que precisar encriptar um novo cartão você precisa gerar uma nova encryption key.\n\nPara gerar uma encryption key é necessário fazer uma requisição ``POST`` para a rota ``/encryption_keys`` da API enviando como parâmetro seu\n``merchant_id``. Ela não usa o token da API (nunca o coloque no front-end): o ``merchant_id`` identifica a sua conta, e um\n``merchant_id`` que não existe responde 401.\n\nA requisição deverá ter esse formato:\n```\ncurl -X POST https://payments.cefis.com.br/api/v1/encryption_keys -H 'Content-Type: application/json' -d '{\"merchant_id\":\"SEU_MERCHANT_ID\"}'\n```\n\nComo resposta você receberá um objeto JSON no seguinte formato:\n```\n{\n \"id\": 1111,\n \"public_key\": \"-----BEGIN PUBLIC KEY-----\\n ... \\n-----END PUBLIC KEY-----\\n\",\n \"ip_address\": \"000.000.000.000\",\n \"created_at\": \"2017-07-03\",\n}\n```\n\n## Encriptando os dados do cartão\nPara encriptar os dados do cartão primeiro você precisa formatá-los de forma correta, para isso crie uma string JSON\ncontendo todos os dados do cartão no seguinte formato:\n\n```\n{\"card_number\":\"1111111111111111\",\"card_holder_name\":\"Jose Silva\",\"card_expiration_date\":\"11/2021\",\"card_cvv\":\"111\"}\n```\n\nEm seguida faça a criptografia RSA dessa string utilizando a chave pública (public_key) gerada no passo anterior, com\npadding do tipo PKCS1.\n\nApós criptografar os dados converta a string resultante para base64 e você terá um resultado parecido com esse:\n\n```\nGprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nO último passo é concatenar o id da sua encryption key (recebido como resposta da requisição anterior) com a string\nem base64 que representa os dados do cartão, da seguinte forma:\n\n``encryption_key_id + \"_\" + base64_encrypted_card``\n\nO resultado será o seu card hash:\n\n```\n1111_GprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nPronto, agora os dados do cartão do cliente já estão em um formato seguro para serem transportados pela rede, podendo\nagora ser enviados para o seu back-end dar sequência ao fluxo. Vale lembrar que cada card hash pode ser usado apenas\numa vez e além disso tem uma validade máxima de 30 minutos após a geração da encryption key. Caso seja necessário utilizar\no cartão mais de uma vez faça uma requisição para a rota de cartões e salve esse cartão vinculado ao usuário que o detém,\nassim você receberá um ID único que poderá ser usado para realizar mais transações com o mesmo cartão.\n"
},
"paths": {
"/customers": {
"get": {
"summary": "Obter detalhes do cliente",
"tags": [
"Clientes"
],
"description": "Retorna os detalhes de um cliente específico, com base no ID fornecido. **Nota:** É necessário fornecer o ID do cliente para obter os detalhes.\n",
"responses": {
"200": {
"description": "Detalhes do cliente retornados com sucesso",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CustomerDetailsResponse"
}
}
}
},
"401": {
"$ref": "#/components/responses/401"
},
"422": {
"$ref": "#/components/responses/422"
},
"500": {
"$ref": "#/components/responses/500"
}
}
}
}
},
"components": {
"securitySchemes": {
"Bearer": {
"type": "apiKey",
"in": "header",
"name": "Authorization",
"description": "Todas as requisições que requerem autenticação devem incluir no cabeçalho `Authorization` o token de API enviado pela nossa equipe. O token deve ser fornecido no seguinte formato:\n```\nAuthorization: Bearer \n```"
}
},
"responses": {
"401": {
"description": "Não autenticado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "AUTHENTICATION_ERROR",
"message": "Não autenticado.",
"timestamp": "2026-10-22T12:03:44+00:00",
"request_id": "f2a7e962-6083-4525-816e-f14d4a602e0a",
"documentation_url": "https://docs.ninepay.com.br"
}
}
}
},
"422": {
"description": "Erro na validação dos dados",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "VALIDATION_ERROR",
"message": "Os dados informados são inválidos.",
"errors": {
"email": [
"O campo email é obrigatório."
]
},
"timestamp": "2026-10-22T12:03:54+00:00",
"request_id": "64d62d36-e797-45ed-a9d5-c203bde81032",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Corrija os campos e tente novamente."
}
}
}
},
"500": {
"description": "Erro inesperado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "UNEXPECTED_ERROR",
"message": "Houve um erro inesperado.",
"timestamp": "2026-10-22T12:04:46+00:00",
"request_id": "868443d3-38fd-4c92-8ea8-7cccbbce4308",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Verifique todos os parâmetros da requisição. Se o erro persistir, entre em contato com nossa equipe em ti@ninepay.com.br."
}
}
}
}
},
"schemas": {
"ApiError": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "O código do erro. Ex.: `VALIDATION_ERROR`, `FORBIDDEN_ERROR`, `UNEXPECTED_ERROR`."
},
"message": {
"type": "string",
"description": "A mensagem do erro."
},
"errors": {
"type": "object",
"description": "Os erros de cada campo, quando o `code` é `VALIDATION_ERROR`.",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "A data e hora do erro, em UTC."
},
"request_id": {
"type": "string",
"description": "Um identificador único gerado para esta resposta de erro."
},
"documentation_url": {
"type": "string",
"description": "O endereço desta documentação."
},
"suggestion": {
"type": "string",
"description": "Uma sugestão de como resolver o erro."
}
}
},
"CustomerDetailsResponse": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "O ID do cliente."
},
"name": {
"type": "string",
"description": "O nome do cliente."
},
"email": {
"type": "string",
"description": "O email do cliente."
},
"cc_emails": {
"type": "string",
"description": "Os emails CC do cliente."
},
"cpf": {
"type": "string",
"description": "O CPF do cliente se pessoa física."
},
"cnpj": {
"type": "string",
"description": "O CNPJ do cliente se pessoa jurídica."
},
"phone": {
"type": "string",
"description": "O telefone do cliente."
},
"cep": {
"type": "string",
"description": "O CEP do cliente."
},
"address": {
"type": "string",
"description": "O endereço do cliente."
},
"number": {
"type": "string",
"description": "O número do endereço do cliente."
},
"complement": {
"type": "string",
"description": "O complemento do endereço do cliente."
},
"district": {
"type": "string",
"description": "O bairro do cliente."
},
"city": {
"type": "string",
"description": "A cidade do cliente."
},
"state": {
"type": "string",
"description": "A sigla do estado do cliente."
},
"country": {
"type": "string",
"description": "A sigla do país do cliente."
},
"state_enrollment": {
"type": "string",
"description": "A inscrição estadual do cliente."
},
"city_enrollment": {
"type": "string",
"description": "A inscrição municipal do cliente."
},
"tax_regime": {
"type": "string",
"description": "O regime tributário do cliente."
},
"special_tax_regime": {
"type": "string",
"description": "O regime tributário especial do cliente."
},
"icms_taxpayer": {
"type": "string",
"description": "O contribuinte do ICMS do cliente."
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o cliente foi criado."
},
"updated_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o cliente foi atualizado."
},
"receipt_config": {
"type": "object",
"description": "A configuração do recibo do cliente."
}
}
}
}
},
"tags": [
{
"name": "Clientes",
"description": "Clientes"
}
],
"x-tagGroups": [
{
"name": "API Calls",
"tags": [
"Pagamentos",
"Clientes",
"Planos",
"Assinaturas",
"Consultas"
]
}
],
"servers": [
{
"url": "https://api.sandbox.cefispay.com.br/api/v1",
"description": "Servidor de Testes (sandbox)"
}
],
"security": [
{
"Bearer": []
}
]
}
```
---
# Criar novo plano
Source: https://docs.ninepay.com.br/reference/criar-novo-plano
Cria um novo plano que será utilizado no fluxo de pagamentos recorrente. O plano define as configurações para as assinaturas que farão parte dele, como valor, periodicidade, métodos aceitos e outras.
# OpenAPI definition
```json
{
"openapi": "3.0.3",
"info": {
"title": "NinePay API",
"version": "1.0",
"x-logo": {
"url": ""
},
"termsOfService": "https://bit.ly/cefispay-contrato",
"contact": {
"name": "NinePay Engineering Team",
"email": "ti@ninepay.com.br"
},
"description": "# Introdução\nBem vindo a referência da **API NinePay**.\nÉ através desta API que você integra o seu sistema ao nosso.\nNossa API é RESTful, e todas suas respostas são em JSON, no endpoint base:\n```\nhttps://payments.cefis.com.br/api/v1/\n```\n\n## Ambientes\nAlém do ambiente de **produção** temos disponível o ambiente **sandbox**\npara a realização de testes de integração. Toda a comunicação com o ambiente sandbox deve ser feita através da url:\n\n```\nhttps://api.sandbox.cefispay.com.br/api/v1/\n```\n\n## Autenticação\nTodas as requisições que requerem autenticação, deverão informar no header `Authorization` o token de api enviado pela nossa equipe, observando sempre o ambiente desejado e no seguinte formato:\n```\nAuthorization: Bearer \n```\n\n## Headers\nRecomendamos que os cabeçalhos da requisições sejam corretamente adicionados para trabalhar com os tipos de dados enviados e recebidos da API:\n - Todas as requisições devem contem o header `Content-Type: application/json`, a menos que o endpoint específico defina diferente\n - Todas as requisições devem contem o header `Accept: application/json`, a menos que o endpoint específico defina diferente\n\n## Respostas\n- Os recursos vêm dentro de `data`: `GET /customers/{id}` responde `{ \"data\": { ... } }`.\n- As criações respondem **201**. `POST /payments` responde `{ \"customer\", \"payment\", \"invoice_url\" }` (o `invoice_url` só no boleto) e `POST /subscriptions` responde `{ \"customer\", \"subscription\" }`.\n- Valores sempre em centavos (inteiro): R$ 50,00 é `5000`.\n\n## Erros\nTodo erro tem o mesmo formato:\n```json\n{\n \"code\": \"VALIDATION_ERROR\",\n \"message\": \"Os dados informados são inválidos.\",\n \"errors\": { \"email\": [\"O campo email é obrigatório.\"] },\n \"timestamp\": \"2026-10-22T12:03:54+00:00\",\n \"request_id\": \"64d62d36-e797-45ed-a9d5-c203bde81032\",\n \"documentation_url\": \"https://docs.ninepay.com.br\",\n \"suggestion\": \"Corrija os campos e tente novamente.\"\n}\n```\n`errors` só vem na validação, com uma **lista** de mensagens por campo. `suggestion` vem quando há uma. Guarde o `request_id` para falar com o suporte.\n\n| `code` | HTTP | Quando |\n| --- | --- | --- |\n| `AUTHENTICATION_ERROR` | 401 | Token ausente ou inválido |\n| `FORBIDDEN_ERROR` | 403 | O recurso não é da sua empresa. Em várias rotas, um id que não existe também responde 403, para não revelar quais ids existem |\n| `COMPANYBLOCKED_ERROR` | 403 | A conta está suspensa |\n| `RESOURCE_NOT_FOUND_ERROR` | 404 | O recurso não existe |\n| `ROUTE_NOT_FOUND_ERROR` | 404 | A rota não existe |\n| `METHOD_NOT_ALLOWED_ERROR` | 405 | O método não vale para a rota (ex.: `PUT /customers` sem o id) |\n| `INVALID_STATE_ERROR` | 400 | O recurso não está num estado que permita a ação (ex.: cancelar um pagamento já pago) |\n| `VALIDATION_ERROR` | 422 | Dados inválidos; veja `errors` |\n| `REFUND_NOT_ALLOWED` | 422 | O pagamento não pode ser reembolsado |\n| `TOO_MANY_ATTEMPTS` | 429 | Muitas requisições; respeite o cabeçalho `Retry-After` |\n| `UNEXPECTED_ERROR` | 500 | Erro nosso; se repetir, fale com o suporte com o `request_id` |\n\n## Paginação\nAs listagens recebem `page` (a partir de 1) e `limit` (itens por página: **10** por padrão, de 1 a **100**). A resposta traz `data` (os itens), `links` e `meta` (`current_page`, `last_page`, `per_page`, `total`).\n\n## Datas\n- Datas de calendário (`due_date`, `next_payment`) vão como `AAAA-MM-DD` na requisição.\n- Nas respostas, os campos de data e hora aparecem em dois formatos: ISO 8601 em UTC (`2026-10-27T03:00:00.000000Z`, em `due_date` e `ref_date` do pagamento) e `AAAA-MM-DD HH:MM:SS` no horário de Brasília (`created_at` e `updated_at`). Leia o campo pelo formato dele.\n\n## Identificadores\nCada recurso tem um `id` numérico e um `uuid`. Use o `id` nas rotas autenticadas e o **`uuid`** em tudo que é público (o link de pagamento, o checkout e o PDF do boleto).\n\n# Hash de cartões\nO hash de um cartão é uma versão criptografada de todos os dados do cartão do cliente, essa é a maneira mais segura de enviar os dados do cartão\ndo seu cliente diretamente para a gente. Abaixo vamos detalhar como ele funciona e como obter um hash a partir dos dados inseridos pelo cliente.\nÉ importante ressaltar que esse fluxo deve ser executado no front-end, seja ele web ou mobile, e que os dados do cartão do cliente nunca devem\nser enviados para o backend, já o hash do cartão pode ser enviado para o backend sem problemas.\n\n## Gerando uma encryption key\nA encryption key consiste basicamente em uma chave pública RSA usada para encriptar os dados do cartão, essa chave só pode ser usada uma vez, então\nsempre que precisar encriptar um novo cartão você precisa gerar uma nova encryption key.\n\nPara gerar uma encryption key é necessário fazer uma requisição ``POST`` para a rota ``/encryption_keys`` da API enviando como parâmetro seu\n``merchant_id``. Ela não usa o token da API (nunca o coloque no front-end): o ``merchant_id`` identifica a sua conta, e um\n``merchant_id`` que não existe responde 401.\n\nA requisição deverá ter esse formato:\n```\ncurl -X POST https://payments.cefis.com.br/api/v1/encryption_keys -H 'Content-Type: application/json' -d '{\"merchant_id\":\"SEU_MERCHANT_ID\"}'\n```\n\nComo resposta você receberá um objeto JSON no seguinte formato:\n```\n{\n \"id\": 1111,\n \"public_key\": \"-----BEGIN PUBLIC KEY-----\\n ... \\n-----END PUBLIC KEY-----\\n\",\n \"ip_address\": \"000.000.000.000\",\n \"created_at\": \"2017-07-03\",\n}\n```\n\n## Encriptando os dados do cartão\nPara encriptar os dados do cartão primeiro você precisa formatá-los de forma correta, para isso crie uma string JSON\ncontendo todos os dados do cartão no seguinte formato:\n\n```\n{\"card_number\":\"1111111111111111\",\"card_holder_name\":\"Jose Silva\",\"card_expiration_date\":\"11/2021\",\"card_cvv\":\"111\"}\n```\n\nEm seguida faça a criptografia RSA dessa string utilizando a chave pública (public_key) gerada no passo anterior, com\npadding do tipo PKCS1.\n\nApós criptografar os dados converta a string resultante para base64 e você terá um resultado parecido com esse:\n\n```\nGprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nO último passo é concatenar o id da sua encryption key (recebido como resposta da requisição anterior) com a string\nem base64 que representa os dados do cartão, da seguinte forma:\n\n``encryption_key_id + \"_\" + base64_encrypted_card``\n\nO resultado será o seu card hash:\n\n```\n1111_GprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nPronto, agora os dados do cartão do cliente já estão em um formato seguro para serem transportados pela rede, podendo\nagora ser enviados para o seu back-end dar sequência ao fluxo. Vale lembrar que cada card hash pode ser usado apenas\numa vez e além disso tem uma validade máxima de 30 minutos após a geração da encryption key. Caso seja necessário utilizar\no cartão mais de uma vez faça uma requisição para a rota de cartões e salve esse cartão vinculado ao usuário que o detém,\nassim você receberá um ID único que poderá ser usado para realizar mais transações com o mesmo cartão.\n"
},
"paths": {
"/plan": {
"post": {
"summary": "Criar novo plano",
"tags": [
"Planos"
],
"description": "Cria um novo plano que será utilizado no fluxo de pagamentos recorrente. O plano define as configurações para as assinaturas que farão parte dele, como valor, periodicidade, métodos aceitos e outras.\n",
"requestBody": {
"$ref": "#/components/requestBodies/PlanBody"
},
"responses": {
"200": {
"description": "Plano criado com sucesso",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Plan"
}
}
}
},
"401": {
"$ref": "#/components/responses/401"
},
"422": {
"$ref": "#/components/responses/422"
},
"500": {
"$ref": "#/components/responses/500"
}
},
"operationId": "createPlan"
}
}
},
"components": {
"securitySchemes": {
"Bearer": {
"type": "apiKey",
"in": "header",
"name": "Authorization",
"description": "Todas as requisições que requerem autenticação devem incluir no cabeçalho `Authorization` o token de API enviado pela nossa equipe. O token deve ser fornecido no seguinte formato:\n```\nAuthorization: Bearer \n```"
}
},
"responses": {
"401": {
"description": "Não autenticado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "AUTHENTICATION_ERROR",
"message": "Não autenticado.",
"timestamp": "2026-10-22T12:03:44+00:00",
"request_id": "f2a7e962-6083-4525-816e-f14d4a602e0a",
"documentation_url": "https://docs.ninepay.com.br"
}
}
}
},
"422": {
"description": "Erro na validação dos dados",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "VALIDATION_ERROR",
"message": "Os dados informados são inválidos.",
"errors": {
"email": [
"O campo email é obrigatório."
]
},
"timestamp": "2026-10-22T12:03:54+00:00",
"request_id": "64d62d36-e797-45ed-a9d5-c203bde81032",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Corrija os campos e tente novamente."
}
}
}
},
"500": {
"description": "Erro inesperado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "UNEXPECTED_ERROR",
"message": "Houve um erro inesperado.",
"timestamp": "2026-10-22T12:04:46+00:00",
"request_id": "868443d3-38fd-4c92-8ea8-7cccbbce4308",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Verifique todos os parâmetros da requisição. Se o erro persistir, entre em contato com nossa equipe em ti@ninepay.com.br."
}
}
}
}
},
"schemas": {
"ApiError": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "O código do erro. Ex.: `VALIDATION_ERROR`, `FORBIDDEN_ERROR`, `UNEXPECTED_ERROR`."
},
"message": {
"type": "string",
"description": "A mensagem do erro."
},
"errors": {
"type": "object",
"description": "Os erros de cada campo, quando o `code` é `VALIDATION_ERROR`.",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "A data e hora do erro, em UTC."
},
"request_id": {
"type": "string",
"description": "Um identificador único gerado para esta resposta de erro."
},
"documentation_url": {
"type": "string",
"description": "O endereço desta documentação."
},
"suggestion": {
"type": "string",
"description": "Uma sugestão de como resolver o erro."
}
}
},
"Plan": {
"type": "object",
"properties": {
"id": {
"description": "O id do plano na NinePay.",
"type": "integer",
"example": 42,
"readOnly": true
},
"name": {
"description": "O nome do plano.",
"type": "string",
"example": "Plano Recorrente Acme"
},
"methods": {
"description": "Os métodos de pagamento que são aceitos neste plano.",
"type": "array",
"items": {
"$ref": "#/components/schemas/PaymentMethods"
}
},
"value": {
"description": "O valor do plano em centavos.",
"type": "number",
"example": 2500
},
"interval": {
"description": "O intervalo, ou seja, a periodicidade de cobrança do plano. Por exemplo, para cobrar a cada mês o intervalo é 1.",
"type": "number",
"example": 1
},
"interval_type": {
"description": "O tipo de ciclo que será usado na contagem dos intervalos. Podendo ser dias, meses ou anos. Por exemplo, para cobrar mensalmente defina `interval` como `1` e `interval_type` como `months`",
"$ref": "#/components/schemas/PlanIntervals",
"example": "months"
},
"dunning_id": {
"description": "A régua de cobrança que será usada para enviar comunicações sobre as assinaturas criadas com este plano.",
"type": "number",
"example": 1
},
"created_at": {
"description": "Data de criação",
"type": "string",
"format": "date-time",
"example": "2017-07-21 05:20:00"
}
}
},
"PlanIntervals": {
"type": "string",
"enum": [
"days",
"months",
"years"
]
},
"PaymentMethods": {
"type": "string",
"enum": [
"credit",
"billet",
"pix"
]
},
"PlanBody": {
"type": "object",
"required": [
"name",
"methods",
"value",
"interval",
"interval_type",
"dunning_id"
],
"properties": {
"name": {
"description": "O nome do plano.",
"type": "string",
"example": "Plano Recorrente Acme"
},
"methods": {
"description": "Os métodos de pagamento que serão aceitos neste plano.",
"type": "array",
"items": {
"$ref": "#/components/schemas/PaymentMethods"
}
},
"value": {
"description": "O valor do plano em centavos.",
"type": "number",
"example": 2500
},
"status": {
"description": "O status do plano.",
"$ref": "#/components/schemas/PlanStatus",
"example": "credit"
},
"interval": {
"description": "O intervalo, ou seja, a periodicidade de cobrança do plano. Por exemplo, para cobrar a cada mês o intervalo é 1.",
"type": "number",
"example": 1
},
"interval_type": {
"description": "O tipo de ciclo que será usado na contagem dos intervalos. Podendo ser dias, meses ou anos. Por exemplo, para cobrar mensalmente defina `interval` como `1` e `interval_type` como `months`",
"$ref": "#/components/schemas/PlanIntervals",
"example": "months"
},
"dunning_id": {
"description": "Essa configuração se refere a régua de cobrança que será usada para enviar comunicações sobre as assinaturas criadas com este plano. Para testes utilize o valor `1` (régua padrão)",
"type": "number",
"example": 1
}
}
},
"PlanStatus": {
"type": "string",
"enum": [
"active",
"inactive"
]
}
},
"requestBodies": {
"PlanBody": {
"required": true,
"description": "Descreve os dados a serem incluídos no corpo da requisição.\n",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PlanBody"
}
}
}
}
}
},
"tags": [
{
"name": "Planos",
"description": "Planos"
}
],
"x-tagGroups": [
{
"name": "API Calls",
"tags": [
"Pagamentos",
"Clientes",
"Planos",
"Assinaturas",
"Consultas"
]
}
],
"servers": [
{
"url": "https://api.sandbox.cefispay.com.br/api/v1",
"description": "Servidor de Testes (sandbox)"
}
],
"security": [
{
"Bearer": []
}
]
}
```
---
# Atualizar plano existente
Source: https://docs.ninepay.com.br/reference/atualizar-plano-existente
Atualiza um plano existente com base no ID fornecido. **Nota:** É necessário fornecer o ID do plano que deseja atualizar.
# OpenAPI definition
```json
{
"openapi": "3.0.3",
"info": {
"title": "NinePay API",
"version": "1.0",
"x-logo": {
"url": ""
},
"termsOfService": "https://bit.ly/cefispay-contrato",
"contact": {
"name": "NinePay Engineering Team",
"email": "ti@ninepay.com.br"
},
"description": "# Introdução\nBem vindo a referência da **API NinePay**.\nÉ através desta API que você integra o seu sistema ao nosso.\nNossa API é RESTful, e todas suas respostas são em JSON, no endpoint base:\n```\nhttps://payments.cefis.com.br/api/v1/\n```\n\n## Ambientes\nAlém do ambiente de **produção** temos disponível o ambiente **sandbox**\npara a realização de testes de integração. Toda a comunicação com o ambiente sandbox deve ser feita através da url:\n\n```\nhttps://api.sandbox.cefispay.com.br/api/v1/\n```\n\n## Autenticação\nTodas as requisições que requerem autenticação, deverão informar no header `Authorization` o token de api enviado pela nossa equipe, observando sempre o ambiente desejado e no seguinte formato:\n```\nAuthorization: Bearer \n```\n\n## Headers\nRecomendamos que os cabeçalhos da requisições sejam corretamente adicionados para trabalhar com os tipos de dados enviados e recebidos da API:\n - Todas as requisições devem contem o header `Content-Type: application/json`, a menos que o endpoint específico defina diferente\n - Todas as requisições devem contem o header `Accept: application/json`, a menos que o endpoint específico defina diferente\n\n## Respostas\n- Os recursos vêm dentro de `data`: `GET /customers/{id}` responde `{ \"data\": { ... } }`.\n- As criações respondem **201**. `POST /payments` responde `{ \"customer\", \"payment\", \"invoice_url\" }` (o `invoice_url` só no boleto) e `POST /subscriptions` responde `{ \"customer\", \"subscription\" }`.\n- Valores sempre em centavos (inteiro): R$ 50,00 é `5000`.\n\n## Erros\nTodo erro tem o mesmo formato:\n```json\n{\n \"code\": \"VALIDATION_ERROR\",\n \"message\": \"Os dados informados são inválidos.\",\n \"errors\": { \"email\": [\"O campo email é obrigatório.\"] },\n \"timestamp\": \"2026-10-22T12:03:54+00:00\",\n \"request_id\": \"64d62d36-e797-45ed-a9d5-c203bde81032\",\n \"documentation_url\": \"https://docs.ninepay.com.br\",\n \"suggestion\": \"Corrija os campos e tente novamente.\"\n}\n```\n`errors` só vem na validação, com uma **lista** de mensagens por campo. `suggestion` vem quando há uma. Guarde o `request_id` para falar com o suporte.\n\n| `code` | HTTP | Quando |\n| --- | --- | --- |\n| `AUTHENTICATION_ERROR` | 401 | Token ausente ou inválido |\n| `FORBIDDEN_ERROR` | 403 | O recurso não é da sua empresa. Em várias rotas, um id que não existe também responde 403, para não revelar quais ids existem |\n| `COMPANYBLOCKED_ERROR` | 403 | A conta está suspensa |\n| `RESOURCE_NOT_FOUND_ERROR` | 404 | O recurso não existe |\n| `ROUTE_NOT_FOUND_ERROR` | 404 | A rota não existe |\n| `METHOD_NOT_ALLOWED_ERROR` | 405 | O método não vale para a rota (ex.: `PUT /customers` sem o id) |\n| `INVALID_STATE_ERROR` | 400 | O recurso não está num estado que permita a ação (ex.: cancelar um pagamento já pago) |\n| `VALIDATION_ERROR` | 422 | Dados inválidos; veja `errors` |\n| `REFUND_NOT_ALLOWED` | 422 | O pagamento não pode ser reembolsado |\n| `TOO_MANY_ATTEMPTS` | 429 | Muitas requisições; respeite o cabeçalho `Retry-After` |\n| `UNEXPECTED_ERROR` | 500 | Erro nosso; se repetir, fale com o suporte com o `request_id` |\n\n## Paginação\nAs listagens recebem `page` (a partir de 1) e `limit` (itens por página: **10** por padrão, de 1 a **100**). A resposta traz `data` (os itens), `links` e `meta` (`current_page`, `last_page`, `per_page`, `total`).\n\n## Datas\n- Datas de calendário (`due_date`, `next_payment`) vão como `AAAA-MM-DD` na requisição.\n- Nas respostas, os campos de data e hora aparecem em dois formatos: ISO 8601 em UTC (`2026-10-27T03:00:00.000000Z`, em `due_date` e `ref_date` do pagamento) e `AAAA-MM-DD HH:MM:SS` no horário de Brasília (`created_at` e `updated_at`). Leia o campo pelo formato dele.\n\n## Identificadores\nCada recurso tem um `id` numérico e um `uuid`. Use o `id` nas rotas autenticadas e o **`uuid`** em tudo que é público (o link de pagamento, o checkout e o PDF do boleto).\n\n# Hash de cartões\nO hash de um cartão é uma versão criptografada de todos os dados do cartão do cliente, essa é a maneira mais segura de enviar os dados do cartão\ndo seu cliente diretamente para a gente. Abaixo vamos detalhar como ele funciona e como obter um hash a partir dos dados inseridos pelo cliente.\nÉ importante ressaltar que esse fluxo deve ser executado no front-end, seja ele web ou mobile, e que os dados do cartão do cliente nunca devem\nser enviados para o backend, já o hash do cartão pode ser enviado para o backend sem problemas.\n\n## Gerando uma encryption key\nA encryption key consiste basicamente em uma chave pública RSA usada para encriptar os dados do cartão, essa chave só pode ser usada uma vez, então\nsempre que precisar encriptar um novo cartão você precisa gerar uma nova encryption key.\n\nPara gerar uma encryption key é necessário fazer uma requisição ``POST`` para a rota ``/encryption_keys`` da API enviando como parâmetro seu\n``merchant_id``. Ela não usa o token da API (nunca o coloque no front-end): o ``merchant_id`` identifica a sua conta, e um\n``merchant_id`` que não existe responde 401.\n\nA requisição deverá ter esse formato:\n```\ncurl -X POST https://payments.cefis.com.br/api/v1/encryption_keys -H 'Content-Type: application/json' -d '{\"merchant_id\":\"SEU_MERCHANT_ID\"}'\n```\n\nComo resposta você receberá um objeto JSON no seguinte formato:\n```\n{\n \"id\": 1111,\n \"public_key\": \"-----BEGIN PUBLIC KEY-----\\n ... \\n-----END PUBLIC KEY-----\\n\",\n \"ip_address\": \"000.000.000.000\",\n \"created_at\": \"2017-07-03\",\n}\n```\n\n## Encriptando os dados do cartão\nPara encriptar os dados do cartão primeiro você precisa formatá-los de forma correta, para isso crie uma string JSON\ncontendo todos os dados do cartão no seguinte formato:\n\n```\n{\"card_number\":\"1111111111111111\",\"card_holder_name\":\"Jose Silva\",\"card_expiration_date\":\"11/2021\",\"card_cvv\":\"111\"}\n```\n\nEm seguida faça a criptografia RSA dessa string utilizando a chave pública (public_key) gerada no passo anterior, com\npadding do tipo PKCS1.\n\nApós criptografar os dados converta a string resultante para base64 e você terá um resultado parecido com esse:\n\n```\nGprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nO último passo é concatenar o id da sua encryption key (recebido como resposta da requisição anterior) com a string\nem base64 que representa os dados do cartão, da seguinte forma:\n\n``encryption_key_id + \"_\" + base64_encrypted_card``\n\nO resultado será o seu card hash:\n\n```\n1111_GprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nPronto, agora os dados do cartão do cliente já estão em um formato seguro para serem transportados pela rede, podendo\nagora ser enviados para o seu back-end dar sequência ao fluxo. Vale lembrar que cada card hash pode ser usado apenas\numa vez e além disso tem uma validade máxima de 30 minutos após a geração da encryption key. Caso seja necessário utilizar\no cartão mais de uma vez faça uma requisição para a rota de cartões e salve esse cartão vinculado ao usuário que o detém,\nassim você receberá um ID único que poderá ser usado para realizar mais transações com o mesmo cartão.\n"
},
"paths": {
"/plan": {
"put": {
"summary": "Atualizar plano existente",
"tags": [
"Planos"
],
"description": "Atualiza um plano existente com base no ID fornecido. **Nota:** É necessário fornecer o ID do plano que deseja atualizar.\n",
"requestBody": {
"$ref": "#/components/requestBodies/PlanBody"
},
"responses": {
"200": {
"description": "Plano atualizado com sucesso",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PlanUpdateResponse"
}
}
}
},
"401": {
"$ref": "#/components/responses/401"
},
"422": {
"$ref": "#/components/responses/422"
},
"500": {
"$ref": "#/components/responses/500"
}
}
}
}
},
"components": {
"securitySchemes": {
"Bearer": {
"type": "apiKey",
"in": "header",
"name": "Authorization",
"description": "Todas as requisições que requerem autenticação devem incluir no cabeçalho `Authorization` o token de API enviado pela nossa equipe. O token deve ser fornecido no seguinte formato:\n```\nAuthorization: Bearer \n```"
}
},
"responses": {
"401": {
"description": "Não autenticado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "AUTHENTICATION_ERROR",
"message": "Não autenticado.",
"timestamp": "2026-10-22T12:03:44+00:00",
"request_id": "f2a7e962-6083-4525-816e-f14d4a602e0a",
"documentation_url": "https://docs.ninepay.com.br"
}
}
}
},
"422": {
"description": "Erro na validação dos dados",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "VALIDATION_ERROR",
"message": "Os dados informados são inválidos.",
"errors": {
"email": [
"O campo email é obrigatório."
]
},
"timestamp": "2026-10-22T12:03:54+00:00",
"request_id": "64d62d36-e797-45ed-a9d5-c203bde81032",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Corrija os campos e tente novamente."
}
}
}
},
"500": {
"description": "Erro inesperado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "UNEXPECTED_ERROR",
"message": "Houve um erro inesperado.",
"timestamp": "2026-10-22T12:04:46+00:00",
"request_id": "868443d3-38fd-4c92-8ea8-7cccbbce4308",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Verifique todos os parâmetros da requisição. Se o erro persistir, entre em contato com nossa equipe em ti@ninepay.com.br."
}
}
}
}
},
"schemas": {
"ApiError": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "O código do erro. Ex.: `VALIDATION_ERROR`, `FORBIDDEN_ERROR`, `UNEXPECTED_ERROR`."
},
"message": {
"type": "string",
"description": "A mensagem do erro."
},
"errors": {
"type": "object",
"description": "Os erros de cada campo, quando o `code` é `VALIDATION_ERROR`.",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "A data e hora do erro, em UTC."
},
"request_id": {
"type": "string",
"description": "Um identificador único gerado para esta resposta de erro."
},
"documentation_url": {
"type": "string",
"description": "O endereço desta documentação."
},
"suggestion": {
"type": "string",
"description": "Uma sugestão de como resolver o erro."
}
}
},
"PlanUpdateResponse": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "O ID do plano."
},
"uuid": {
"type": "string",
"description": "O UUID do plano."
},
"name": {
"type": "string",
"description": "O nome do plano."
},
"public_name": {
"type": "string",
"description": "O nome público do plano."
},
"methods": {
"type": "array",
"description": "Os métodos de pagamento do plano."
},
"value": {
"type": "number",
"description": "O valor do plano."
},
"fine": {
"type": "number",
"description": "A multa do plano."
},
"interest": {
"type": "number",
"description": "O juros do plano."
},
"interval": {
"type": "number",
"description": "O intervalo do plano."
},
"interval_type": {
"type": "string",
"description": "O tipo de intervalo do plano."
},
"charges": {
"type": "number",
"description": "As cobranças do plano."
},
"trial_days": {
"type": "number",
"description": "Os dias de teste do plano."
},
"retry_days": {
"type": "number",
"description": "Os dias de tentativa do plano."
},
"automatic_cancel": {
"type": "boolean",
"description": "O cancelamento automático do plano."
},
"url": {
"type": "string",
"description": "A URL do plano."
},
"custom_layout_enabled": {
"type": "boolean",
"description": "A habilitação do layout personalizado do plano."
},
"custom_layout": {
"type": "string",
"description": "O layout personalizado do plano."
},
"redirect_uri": {
"type": "string",
"description": "A URI de redirecionamento do plano."
},
"status": {
"$ref": "#/components/schemas/PlanStatus"
},
"custom_fields": {
"type": "array",
"description": "Os campos personalizados do plano."
},
"billing_products": {
"type": "array",
"description": "Os produtos de cobrança do plano."
},
"company": {
"type": "object",
"description": "A empresa do plano."
},
"charge_enabled": {
"type": "boolean",
"description": "A habilitação da cobrança do plano."
},
"billing_settings": {
"type": "object",
"description": "As configurações de cobrança do plano."
},
"dunning": {
"type": "object",
"description": "O dunning do plano."
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o plano foi criado."
},
"updated_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o plano foi atualizado."
}
}
},
"PlanStatus": {
"type": "string",
"enum": [
"active",
"inactive"
]
},
"PlanBody": {
"type": "object",
"required": [
"name",
"methods",
"value",
"interval",
"interval_type",
"dunning_id"
],
"properties": {
"name": {
"description": "O nome do plano.",
"type": "string",
"example": "Plano Recorrente Acme"
},
"methods": {
"description": "Os métodos de pagamento que serão aceitos neste plano.",
"type": "array",
"items": {
"$ref": "#/components/schemas/PaymentMethods"
}
},
"value": {
"description": "O valor do plano em centavos.",
"type": "number",
"example": 2500
},
"status": {
"description": "O status do plano.",
"$ref": "#/components/schemas/PlanStatus",
"example": "credit"
},
"interval": {
"description": "O intervalo, ou seja, a periodicidade de cobrança do plano. Por exemplo, para cobrar a cada mês o intervalo é 1.",
"type": "number",
"example": 1
},
"interval_type": {
"description": "O tipo de ciclo que será usado na contagem dos intervalos. Podendo ser dias, meses ou anos. Por exemplo, para cobrar mensalmente defina `interval` como `1` e `interval_type` como `months`",
"$ref": "#/components/schemas/PlanIntervals",
"example": "months"
},
"dunning_id": {
"description": "Essa configuração se refere a régua de cobrança que será usada para enviar comunicações sobre as assinaturas criadas com este plano. Para testes utilize o valor `1` (régua padrão)",
"type": "number",
"example": 1
}
}
},
"PlanIntervals": {
"type": "string",
"enum": [
"days",
"months",
"years"
]
},
"PaymentMethods": {
"type": "string",
"enum": [
"credit",
"billet",
"pix"
]
}
},
"requestBodies": {
"PlanBody": {
"required": true,
"description": "Descreve os dados a serem incluídos no corpo da requisição.\n",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PlanBody"
}
}
}
}
}
},
"tags": [
{
"name": "Planos",
"description": "Planos"
}
],
"x-tagGroups": [
{
"name": "API Calls",
"tags": [
"Pagamentos",
"Clientes",
"Planos",
"Assinaturas",
"Consultas"
]
}
],
"servers": [
{
"url": "https://api.sandbox.cefispay.com.br/api/v1",
"description": "Servidor de Testes (sandbox)"
}
],
"security": [
{
"Bearer": []
}
]
}
```
---
# Obter detalhes do plano
Source: https://docs.ninepay.com.br/reference/obter-detalhes-do-plano
Retorna os detalhes de um plano específico, com base no ID fornecido. **Nota:** É necessário fornecer o ID do plano para obter os detalhes.
# OpenAPI definition
```json
{
"openapi": "3.0.3",
"info": {
"title": "NinePay API",
"version": "1.0",
"x-logo": {
"url": ""
},
"termsOfService": "https://bit.ly/cefispay-contrato",
"contact": {
"name": "NinePay Engineering Team",
"email": "ti@ninepay.com.br"
},
"description": "# Introdução\nBem vindo a referência da **API NinePay**.\nÉ através desta API que você integra o seu sistema ao nosso.\nNossa API é RESTful, e todas suas respostas são em JSON, no endpoint base:\n```\nhttps://payments.cefis.com.br/api/v1/\n```\n\n## Ambientes\nAlém do ambiente de **produção** temos disponível o ambiente **sandbox**\npara a realização de testes de integração. Toda a comunicação com o ambiente sandbox deve ser feita através da url:\n\n```\nhttps://api.sandbox.cefispay.com.br/api/v1/\n```\n\n## Autenticação\nTodas as requisições que requerem autenticação, deverão informar no header `Authorization` o token de api enviado pela nossa equipe, observando sempre o ambiente desejado e no seguinte formato:\n```\nAuthorization: Bearer \n```\n\n## Headers\nRecomendamos que os cabeçalhos da requisições sejam corretamente adicionados para trabalhar com os tipos de dados enviados e recebidos da API:\n - Todas as requisições devem contem o header `Content-Type: application/json`, a menos que o endpoint específico defina diferente\n - Todas as requisições devem contem o header `Accept: application/json`, a menos que o endpoint específico defina diferente\n\n## Respostas\n- Os recursos vêm dentro de `data`: `GET /customers/{id}` responde `{ \"data\": { ... } }`.\n- As criações respondem **201**. `POST /payments` responde `{ \"customer\", \"payment\", \"invoice_url\" }` (o `invoice_url` só no boleto) e `POST /subscriptions` responde `{ \"customer\", \"subscription\" }`.\n- Valores sempre em centavos (inteiro): R$ 50,00 é `5000`.\n\n## Erros\nTodo erro tem o mesmo formato:\n```json\n{\n \"code\": \"VALIDATION_ERROR\",\n \"message\": \"Os dados informados são inválidos.\",\n \"errors\": { \"email\": [\"O campo email é obrigatório.\"] },\n \"timestamp\": \"2026-10-22T12:03:54+00:00\",\n \"request_id\": \"64d62d36-e797-45ed-a9d5-c203bde81032\",\n \"documentation_url\": \"https://docs.ninepay.com.br\",\n \"suggestion\": \"Corrija os campos e tente novamente.\"\n}\n```\n`errors` só vem na validação, com uma **lista** de mensagens por campo. `suggestion` vem quando há uma. Guarde o `request_id` para falar com o suporte.\n\n| `code` | HTTP | Quando |\n| --- | --- | --- |\n| `AUTHENTICATION_ERROR` | 401 | Token ausente ou inválido |\n| `FORBIDDEN_ERROR` | 403 | O recurso não é da sua empresa. Em várias rotas, um id que não existe também responde 403, para não revelar quais ids existem |\n| `COMPANYBLOCKED_ERROR` | 403 | A conta está suspensa |\n| `RESOURCE_NOT_FOUND_ERROR` | 404 | O recurso não existe |\n| `ROUTE_NOT_FOUND_ERROR` | 404 | A rota não existe |\n| `METHOD_NOT_ALLOWED_ERROR` | 405 | O método não vale para a rota (ex.: `PUT /customers` sem o id) |\n| `INVALID_STATE_ERROR` | 400 | O recurso não está num estado que permita a ação (ex.: cancelar um pagamento já pago) |\n| `VALIDATION_ERROR` | 422 | Dados inválidos; veja `errors` |\n| `REFUND_NOT_ALLOWED` | 422 | O pagamento não pode ser reembolsado |\n| `TOO_MANY_ATTEMPTS` | 429 | Muitas requisições; respeite o cabeçalho `Retry-After` |\n| `UNEXPECTED_ERROR` | 500 | Erro nosso; se repetir, fale com o suporte com o `request_id` |\n\n## Paginação\nAs listagens recebem `page` (a partir de 1) e `limit` (itens por página: **10** por padrão, de 1 a **100**). A resposta traz `data` (os itens), `links` e `meta` (`current_page`, `last_page`, `per_page`, `total`).\n\n## Datas\n- Datas de calendário (`due_date`, `next_payment`) vão como `AAAA-MM-DD` na requisição.\n- Nas respostas, os campos de data e hora aparecem em dois formatos: ISO 8601 em UTC (`2026-10-27T03:00:00.000000Z`, em `due_date` e `ref_date` do pagamento) e `AAAA-MM-DD HH:MM:SS` no horário de Brasília (`created_at` e `updated_at`). Leia o campo pelo formato dele.\n\n## Identificadores\nCada recurso tem um `id` numérico e um `uuid`. Use o `id` nas rotas autenticadas e o **`uuid`** em tudo que é público (o link de pagamento, o checkout e o PDF do boleto).\n\n# Hash de cartões\nO hash de um cartão é uma versão criptografada de todos os dados do cartão do cliente, essa é a maneira mais segura de enviar os dados do cartão\ndo seu cliente diretamente para a gente. Abaixo vamos detalhar como ele funciona e como obter um hash a partir dos dados inseridos pelo cliente.\nÉ importante ressaltar que esse fluxo deve ser executado no front-end, seja ele web ou mobile, e que os dados do cartão do cliente nunca devem\nser enviados para o backend, já o hash do cartão pode ser enviado para o backend sem problemas.\n\n## Gerando uma encryption key\nA encryption key consiste basicamente em uma chave pública RSA usada para encriptar os dados do cartão, essa chave só pode ser usada uma vez, então\nsempre que precisar encriptar um novo cartão você precisa gerar uma nova encryption key.\n\nPara gerar uma encryption key é necessário fazer uma requisição ``POST`` para a rota ``/encryption_keys`` da API enviando como parâmetro seu\n``merchant_id``. Ela não usa o token da API (nunca o coloque no front-end): o ``merchant_id`` identifica a sua conta, e um\n``merchant_id`` que não existe responde 401.\n\nA requisição deverá ter esse formato:\n```\ncurl -X POST https://payments.cefis.com.br/api/v1/encryption_keys -H 'Content-Type: application/json' -d '{\"merchant_id\":\"SEU_MERCHANT_ID\"}'\n```\n\nComo resposta você receberá um objeto JSON no seguinte formato:\n```\n{\n \"id\": 1111,\n \"public_key\": \"-----BEGIN PUBLIC KEY-----\\n ... \\n-----END PUBLIC KEY-----\\n\",\n \"ip_address\": \"000.000.000.000\",\n \"created_at\": \"2017-07-03\",\n}\n```\n\n## Encriptando os dados do cartão\nPara encriptar os dados do cartão primeiro você precisa formatá-los de forma correta, para isso crie uma string JSON\ncontendo todos os dados do cartão no seguinte formato:\n\n```\n{\"card_number\":\"1111111111111111\",\"card_holder_name\":\"Jose Silva\",\"card_expiration_date\":\"11/2021\",\"card_cvv\":\"111\"}\n```\n\nEm seguida faça a criptografia RSA dessa string utilizando a chave pública (public_key) gerada no passo anterior, com\npadding do tipo PKCS1.\n\nApós criptografar os dados converta a string resultante para base64 e você terá um resultado parecido com esse:\n\n```\nGprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nO último passo é concatenar o id da sua encryption key (recebido como resposta da requisição anterior) com a string\nem base64 que representa os dados do cartão, da seguinte forma:\n\n``encryption_key_id + \"_\" + base64_encrypted_card``\n\nO resultado será o seu card hash:\n\n```\n1111_GprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nPronto, agora os dados do cartão do cliente já estão em um formato seguro para serem transportados pela rede, podendo\nagora ser enviados para o seu back-end dar sequência ao fluxo. Vale lembrar que cada card hash pode ser usado apenas\numa vez e além disso tem uma validade máxima de 30 minutos após a geração da encryption key. Caso seja necessário utilizar\no cartão mais de uma vez faça uma requisição para a rota de cartões e salve esse cartão vinculado ao usuário que o detém,\nassim você receberá um ID único que poderá ser usado para realizar mais transações com o mesmo cartão.\n"
},
"paths": {
"/plan": {
"get": {
"summary": "Obter detalhes do plano",
"tags": [
"Planos"
],
"description": "Retorna os detalhes de um plano específico, com base no ID fornecido. **Nota:** É necessário fornecer o ID do plano para obter os detalhes.\n",
"responses": {
"200": {
"description": "Detalhes do plano retornados com sucesso",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PlanDetailsResponse"
}
}
}
},
"401": {
"$ref": "#/components/responses/401"
},
"422": {
"$ref": "#/components/responses/422"
},
"500": {
"$ref": "#/components/responses/500"
}
}
}
}
},
"components": {
"securitySchemes": {
"Bearer": {
"type": "apiKey",
"in": "header",
"name": "Authorization",
"description": "Todas as requisições que requerem autenticação devem incluir no cabeçalho `Authorization` o token de API enviado pela nossa equipe. O token deve ser fornecido no seguinte formato:\n```\nAuthorization: Bearer \n```"
}
},
"responses": {
"401": {
"description": "Não autenticado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "AUTHENTICATION_ERROR",
"message": "Não autenticado.",
"timestamp": "2026-10-22T12:03:44+00:00",
"request_id": "f2a7e962-6083-4525-816e-f14d4a602e0a",
"documentation_url": "https://docs.ninepay.com.br"
}
}
}
},
"422": {
"description": "Erro na validação dos dados",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "VALIDATION_ERROR",
"message": "Os dados informados são inválidos.",
"errors": {
"email": [
"O campo email é obrigatório."
]
},
"timestamp": "2026-10-22T12:03:54+00:00",
"request_id": "64d62d36-e797-45ed-a9d5-c203bde81032",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Corrija os campos e tente novamente."
}
}
}
},
"500": {
"description": "Erro inesperado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "UNEXPECTED_ERROR",
"message": "Houve um erro inesperado.",
"timestamp": "2026-10-22T12:04:46+00:00",
"request_id": "868443d3-38fd-4c92-8ea8-7cccbbce4308",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Verifique todos os parâmetros da requisição. Se o erro persistir, entre em contato com nossa equipe em ti@ninepay.com.br."
}
}
}
}
},
"schemas": {
"ApiError": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "O código do erro. Ex.: `VALIDATION_ERROR`, `FORBIDDEN_ERROR`, `UNEXPECTED_ERROR`."
},
"message": {
"type": "string",
"description": "A mensagem do erro."
},
"errors": {
"type": "object",
"description": "Os erros de cada campo, quando o `code` é `VALIDATION_ERROR`.",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "A data e hora do erro, em UTC."
},
"request_id": {
"type": "string",
"description": "Um identificador único gerado para esta resposta de erro."
},
"documentation_url": {
"type": "string",
"description": "O endereço desta documentação."
},
"suggestion": {
"type": "string",
"description": "Uma sugestão de como resolver o erro."
}
}
},
"PlanDetailsResponse": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "O ID do plano."
},
"uuid": {
"type": "string",
"description": "O UUID do plano."
},
"name": {
"type": "string",
"description": "O nome do plano."
},
"public_name": {
"type": "string",
"description": "O nome público do plano."
},
"methods": {
"type": "array",
"description": "Os métodos de pagamento do plano."
},
"value": {
"type": "number",
"description": "O valor do plano."
},
"fine": {
"type": "number",
"description": "A multa do plano."
},
"interest": {
"type": "number",
"description": "O juros do plano."
},
"interval": {
"type": "number",
"description": "O intervalo do plano."
},
"interval_type": {
"type": "string",
"description": "O tipo de intervalo do plano."
},
"charges": {
"type": "number",
"description": "As cobranças do plano."
},
"trial_days": {
"type": "number",
"description": "Os dias de teste do plano."
},
"retry_days": {
"type": "number",
"description": "Os dias de tentativa do plano."
},
"automatic_cancel": {
"type": "boolean",
"description": "O cancelamento automático do plano."
},
"url": {
"type": "string",
"description": "A URL do plano."
},
"custom_layout_enabled": {
"type": "boolean",
"description": "A habilitação do layout personalizado do plano."
},
"custom_layout": {
"type": "string",
"description": "O layout personalizado do plano."
},
"redirect_uri": {
"type": "string",
"description": "A URI de redirecionamento do plano."
},
"status": {
"$ref": "#/components/schemas/PlanStatus"
},
"custom_fields": {
"type": "array",
"description": "Os campos personalizados do plano."
},
"billing_products": {
"type": "array",
"description": "Os produtos de cobrança do plano."
},
"company": {
"type": "object",
"description": "A empresa do plano."
},
"charge_enabled": {
"type": "boolean",
"description": "A habilitação da cobrança do plano."
},
"billing_settings": {
"type": "object",
"description": "As configurações de cobrança do plano."
},
"dunning": {
"type": "object",
"description": "O dunning do plano."
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o plano foi criado."
},
"updated_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que o plano foi atualizado."
}
}
},
"PlanStatus": {
"type": "string",
"enum": [
"active",
"inactive"
]
}
}
},
"tags": [
{
"name": "Planos",
"description": "Planos"
}
],
"x-tagGroups": [
{
"name": "API Calls",
"tags": [
"Pagamentos",
"Clientes",
"Planos",
"Assinaturas",
"Consultas"
]
}
],
"servers": [
{
"url": "https://api.sandbox.cefispay.com.br/api/v1",
"description": "Servidor de Testes (sandbox)"
}
],
"security": [
{
"Bearer": []
}
]
}
```
---
# Criar nova assinatura
Source: https://docs.ninepay.com.br/reference/criar-nova-assinatura
Cria uma nova assinatura, que representa uma cobrança recorrente, vinculando um cliente a um plano específico.
**Cartão de crédito:** se a assinatura for cobrada no cartão, o cadastro do cliente precisa ter CPF ou CNPJ, telefone, CEP e número do endereço. Esses dados são enviados à adquirente como dados do titular, e a cobrança é recusada se algum deles estiver faltando. Recomendamos cadastrar o cliente com o máximo de informações possível, mesmo que hoje você só cobre por boleto ou Pix.
# OpenAPI definition
```json
{
"openapi": "3.0.3",
"info": {
"title": "NinePay API",
"version": "1.0",
"x-logo": {
"url": ""
},
"termsOfService": "https://bit.ly/cefispay-contrato",
"contact": {
"name": "NinePay Engineering Team",
"email": "ti@ninepay.com.br"
},
"description": "# Introdução\nBem vindo a referência da **API NinePay**.\nÉ através desta API que você integra o seu sistema ao nosso.\nNossa API é RESTful, e todas suas respostas são em JSON, no endpoint base:\n```\nhttps://payments.cefis.com.br/api/v1/\n```\n\n## Ambientes\nAlém do ambiente de **produção** temos disponível o ambiente **sandbox**\npara a realização de testes de integração. Toda a comunicação com o ambiente sandbox deve ser feita através da url:\n\n```\nhttps://api.sandbox.cefispay.com.br/api/v1/\n```\n\n## Autenticação\nTodas as requisições que requerem autenticação, deverão informar no header `Authorization` o token de api enviado pela nossa equipe, observando sempre o ambiente desejado e no seguinte formato:\n```\nAuthorization: Bearer \n```\n\n## Headers\nRecomendamos que os cabeçalhos da requisições sejam corretamente adicionados para trabalhar com os tipos de dados enviados e recebidos da API:\n - Todas as requisições devem contem o header `Content-Type: application/json`, a menos que o endpoint específico defina diferente\n - Todas as requisições devem contem o header `Accept: application/json`, a menos que o endpoint específico defina diferente\n\n## Respostas\n- Os recursos vêm dentro de `data`: `GET /customers/{id}` responde `{ \"data\": { ... } }`.\n- As criações respondem **201**. `POST /payments` responde `{ \"customer\", \"payment\", \"invoice_url\" }` (o `invoice_url` só no boleto) e `POST /subscriptions` responde `{ \"customer\", \"subscription\" }`.\n- Valores sempre em centavos (inteiro): R$ 50,00 é `5000`.\n\n## Erros\nTodo erro tem o mesmo formato:\n```json\n{\n \"code\": \"VALIDATION_ERROR\",\n \"message\": \"Os dados informados são inválidos.\",\n \"errors\": { \"email\": [\"O campo email é obrigatório.\"] },\n \"timestamp\": \"2026-10-22T12:03:54+00:00\",\n \"request_id\": \"64d62d36-e797-45ed-a9d5-c203bde81032\",\n \"documentation_url\": \"https://docs.ninepay.com.br\",\n \"suggestion\": \"Corrija os campos e tente novamente.\"\n}\n```\n`errors` só vem na validação, com uma **lista** de mensagens por campo. `suggestion` vem quando há uma. Guarde o `request_id` para falar com o suporte.\n\n| `code` | HTTP | Quando |\n| --- | --- | --- |\n| `AUTHENTICATION_ERROR` | 401 | Token ausente ou inválido |\n| `FORBIDDEN_ERROR` | 403 | O recurso não é da sua empresa. Em várias rotas, um id que não existe também responde 403, para não revelar quais ids existem |\n| `COMPANYBLOCKED_ERROR` | 403 | A conta está suspensa |\n| `RESOURCE_NOT_FOUND_ERROR` | 404 | O recurso não existe |\n| `ROUTE_NOT_FOUND_ERROR` | 404 | A rota não existe |\n| `METHOD_NOT_ALLOWED_ERROR` | 405 | O método não vale para a rota (ex.: `PUT /customers` sem o id) |\n| `INVALID_STATE_ERROR` | 400 | O recurso não está num estado que permita a ação (ex.: cancelar um pagamento já pago) |\n| `VALIDATION_ERROR` | 422 | Dados inválidos; veja `errors` |\n| `REFUND_NOT_ALLOWED` | 422 | O pagamento não pode ser reembolsado |\n| `TOO_MANY_ATTEMPTS` | 429 | Muitas requisições; respeite o cabeçalho `Retry-After` |\n| `UNEXPECTED_ERROR` | 500 | Erro nosso; se repetir, fale com o suporte com o `request_id` |\n\n## Paginação\nAs listagens recebem `page` (a partir de 1) e `limit` (itens por página: **10** por padrão, de 1 a **100**). A resposta traz `data` (os itens), `links` e `meta` (`current_page`, `last_page`, `per_page`, `total`).\n\n## Datas\n- Datas de calendário (`due_date`, `next_payment`) vão como `AAAA-MM-DD` na requisição.\n- Nas respostas, os campos de data e hora aparecem em dois formatos: ISO 8601 em UTC (`2026-10-27T03:00:00.000000Z`, em `due_date` e `ref_date` do pagamento) e `AAAA-MM-DD HH:MM:SS` no horário de Brasília (`created_at` e `updated_at`). Leia o campo pelo formato dele.\n\n## Identificadores\nCada recurso tem um `id` numérico e um `uuid`. Use o `id` nas rotas autenticadas e o **`uuid`** em tudo que é público (o link de pagamento, o checkout e o PDF do boleto).\n\n# Hash de cartões\nO hash de um cartão é uma versão criptografada de todos os dados do cartão do cliente, essa é a maneira mais segura de enviar os dados do cartão\ndo seu cliente diretamente para a gente. Abaixo vamos detalhar como ele funciona e como obter um hash a partir dos dados inseridos pelo cliente.\nÉ importante ressaltar que esse fluxo deve ser executado no front-end, seja ele web ou mobile, e que os dados do cartão do cliente nunca devem\nser enviados para o backend, já o hash do cartão pode ser enviado para o backend sem problemas.\n\n## Gerando uma encryption key\nA encryption key consiste basicamente em uma chave pública RSA usada para encriptar os dados do cartão, essa chave só pode ser usada uma vez, então\nsempre que precisar encriptar um novo cartão você precisa gerar uma nova encryption key.\n\nPara gerar uma encryption key é necessário fazer uma requisição ``POST`` para a rota ``/encryption_keys`` da API enviando como parâmetro seu\n``merchant_id``. Ela não usa o token da API (nunca o coloque no front-end): o ``merchant_id`` identifica a sua conta, e um\n``merchant_id`` que não existe responde 401.\n\nA requisição deverá ter esse formato:\n```\ncurl -X POST https://payments.cefis.com.br/api/v1/encryption_keys -H 'Content-Type: application/json' -d '{\"merchant_id\":\"SEU_MERCHANT_ID\"}'\n```\n\nComo resposta você receberá um objeto JSON no seguinte formato:\n```\n{\n \"id\": 1111,\n \"public_key\": \"-----BEGIN PUBLIC KEY-----\\n ... \\n-----END PUBLIC KEY-----\\n\",\n \"ip_address\": \"000.000.000.000\",\n \"created_at\": \"2017-07-03\",\n}\n```\n\n## Encriptando os dados do cartão\nPara encriptar os dados do cartão primeiro você precisa formatá-los de forma correta, para isso crie uma string JSON\ncontendo todos os dados do cartão no seguinte formato:\n\n```\n{\"card_number\":\"1111111111111111\",\"card_holder_name\":\"Jose Silva\",\"card_expiration_date\":\"11/2021\",\"card_cvv\":\"111\"}\n```\n\nEm seguida faça a criptografia RSA dessa string utilizando a chave pública (public_key) gerada no passo anterior, com\npadding do tipo PKCS1.\n\nApós criptografar os dados converta a string resultante para base64 e você terá um resultado parecido com esse:\n\n```\nGprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nO último passo é concatenar o id da sua encryption key (recebido como resposta da requisição anterior) com a string\nem base64 que representa os dados do cartão, da seguinte forma:\n\n``encryption_key_id + \"_\" + base64_encrypted_card``\n\nO resultado será o seu card hash:\n\n```\n1111_GprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nPronto, agora os dados do cartão do cliente já estão em um formato seguro para serem transportados pela rede, podendo\nagora ser enviados para o seu back-end dar sequência ao fluxo. Vale lembrar que cada card hash pode ser usado apenas\numa vez e além disso tem uma validade máxima de 30 minutos após a geração da encryption key. Caso seja necessário utilizar\no cartão mais de uma vez faça uma requisição para a rota de cartões e salve esse cartão vinculado ao usuário que o detém,\nassim você receberá um ID único que poderá ser usado para realizar mais transações com o mesmo cartão.\n"
},
"paths": {
"/subscriptions": {
"post": {
"summary": "Criar nova assinatura",
"tags": [
"Assinaturas"
],
"description": "Cria uma nova assinatura, que representa uma cobrança recorrente, vinculando um cliente a um plano específico.\n**Cartão de crédito:** se a assinatura for cobrada no cartão, o cadastro do cliente precisa ter CPF ou CNPJ, telefone, CEP e número do endereço. Esses dados são enviados à adquirente como dados do titular, e a cobrança é recusada se algum deles estiver faltando. Recomendamos cadastrar o cliente com o máximo de informações possível, mesmo que hoje você só cobre por boleto ou Pix.\n",
"requestBody": {
"$ref": "#/components/requestBodies/SubscriptionStoreBody"
},
"responses": {
"200": {
"description": "Assinatura criada com sucesso",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SubscriptionStoreResponse"
}
}
}
},
"401": {
"$ref": "#/components/responses/401"
},
"422": {
"$ref": "#/components/responses/422"
},
"500": {
"$ref": "#/components/responses/500"
}
},
"operationId": "createSubscription"
}
}
},
"components": {
"securitySchemes": {
"Bearer": {
"type": "apiKey",
"in": "header",
"name": "Authorization",
"description": "Todas as requisições que requerem autenticação devem incluir no cabeçalho `Authorization` o token de API enviado pela nossa equipe. O token deve ser fornecido no seguinte formato:\n```\nAuthorization: Bearer \n```"
}
},
"responses": {
"401": {
"description": "Não autenticado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "AUTHENTICATION_ERROR",
"message": "Não autenticado.",
"timestamp": "2026-10-22T12:03:44+00:00",
"request_id": "f2a7e962-6083-4525-816e-f14d4a602e0a",
"documentation_url": "https://docs.ninepay.com.br"
}
}
}
},
"422": {
"description": "Erro na validação dos dados",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "VALIDATION_ERROR",
"message": "Os dados informados são inválidos.",
"errors": {
"email": [
"O campo email é obrigatório."
]
},
"timestamp": "2026-10-22T12:03:54+00:00",
"request_id": "64d62d36-e797-45ed-a9d5-c203bde81032",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Corrija os campos e tente novamente."
}
}
}
},
"500": {
"description": "Erro inesperado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "UNEXPECTED_ERROR",
"message": "Houve um erro inesperado.",
"timestamp": "2026-10-22T12:04:46+00:00",
"request_id": "868443d3-38fd-4c92-8ea8-7cccbbce4308",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Verifique todos os parâmetros da requisição. Se o erro persistir, entre em contato com nossa equipe em ti@ninepay.com.br."
}
}
}
}
},
"schemas": {
"ApiError": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "O código do erro. Ex.: `VALIDATION_ERROR`, `FORBIDDEN_ERROR`, `UNEXPECTED_ERROR`."
},
"message": {
"type": "string",
"description": "A mensagem do erro."
},
"errors": {
"type": "object",
"description": "Os erros de cada campo, quando o `code` é `VALIDATION_ERROR`.",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "A data e hora do erro, em UTC."
},
"request_id": {
"type": "string",
"description": "Um identificador único gerado para esta resposta de erro."
},
"documentation_url": {
"type": "string",
"description": "O endereço desta documentação."
},
"suggestion": {
"type": "string",
"description": "Uma sugestão de como resolver o erro."
}
}
},
"SubscriptionStoreResponse": {
"type": "object",
"properties": {
"subscription": {
"$ref": "#/components/schemas/Subscription"
},
"customer": {
"$ref": "#/components/schemas/Customer"
}
}
},
"Customer": {
"type": "object",
"required": [
"id",
"name",
"email",
"cpf",
"cnpj"
],
"properties": {
"id": {
"description": "O id do cliente na NinePay. Obrigatório se os demais dados do usuário não forem informados",
"type": "integer",
"example": 42,
"readOnly": true
},
"name": {
"description": "O nome do cliente. Obrigatório se o `id` não for informado",
"type": "string",
"example": "Jhon Doe"
},
"email": {
"description": "O email do cliente. Obrigatório se o `id` não for informado",
"type": "string",
"example": "jhon@doe.com"
},
"cpf": {
"description": "O cpf do cliente. Obrigatório se o `id` ou o `cnpj` não forem informados",
"type": "string",
"example": "833.828.600-15"
},
"cnpj": {
"description": "O cnpj do cliente. Obrigatório se o `id` ou o `cpf` não forem informados",
"type": "string",
"example": "95.135.209/0001-79"
},
"phone": {
"description": "O telefone celular do cliente, com DDD. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": "(11) 11111-1111"
},
"cep": {
"description": "O CEP do cliente. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": "01423-910"
},
"address": {
"description": "O endereço do cliente",
"type": "string",
"example": "Rua José Maria Lisboa"
},
"number": {
"description": "O número do endereço do cliente. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": 42
},
"district": {
"description": "O bairro do cliente",
"type": "string",
"example": "Jardim Paulista"
},
"city": {
"description": "A cidade do cliente",
"type": "string",
"example": "São Paulo"
},
"state": {
"description": "O estado do cliente",
"type": "string",
"example": "SP"
},
"country": {
"description": "O código do país do cliente, no formato Alpha 2 de acordo com a [ISO 3166](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes).",
"type": "string",
"example": "BR"
}
}
},
"Subscription": {
"type": "object",
"properties": {
"id": {
"description": "O id da assinatura.",
"type": "integer",
"example": 42,
"readOnly": true
},
"uuid": {
"description": "O id publico da assinatura. Esse id pode ser usado para levar o cliente a página de checkout para pagamento.",
"type": "string",
"format": "uuid",
"example": "8b2cad02-06f0-42be-84ac-101b23a1bb0d"
},
"amount": {
"description": "O valor da assinatura em centavos.",
"type": "number",
"example": 2500
},
"plan_id": {
"description": "O id do plano.",
"type": "number",
"example": 2500
},
"status": {
"description": "O status da assinatura.",
"$ref": "#/components/schemas/SubscriptionStatus",
"example": "credit"
},
"created_at": {
"description": "Data de criação.",
"type": "string",
"format": "date-time",
"example": "2017-07-21 05:20:00"
}
}
},
"SubscriptionStatus": {
"type": "string",
"enum": [
"new",
"trial",
"active",
"overdue",
"canceled",
"expired",
"paused"
]
},
"SubscriptionStoreBody": {
"allOf": [
{
"$ref": "#/components/schemas/SubscriptionBody"
},
{
"type": "object",
"properties": {
"products": {
"type": "array",
"description": "Opcional. Os produtos da assinatura, cobrados junto do plano. Enviados aqui, eles entram já na primeira cobrança, e não apenas nas seguintes. Quando o plano tem trial, a primeira cobrança continua sendo R$ 0,00 e os produtos entram na cobrança seguinte ao trial. Os produtos também podem ser anexados depois da criação, pelo endpoint de produtos da assinatura.\n",
"items": {
"type": "object",
"required": [
"identifier",
"value"
],
"properties": {
"identifier": {
"type": "string",
"maxLength": 50,
"description": "O nome do produto, como aparece na cobrança.",
"example": "Membro adicional"
},
"value": {
"type": "integer",
"description": "O valor do produto, em centavos.",
"example": 1290
},
"name": {
"type": "string",
"maxLength": 191,
"description": "Opcional. O que o cliente lê na cobrança. O `identifier` é a chave pela qual o produto é removido, então costuma ser um valor técnico; o `name` é o rótulo apresentável. Sem `name`, o `identifier` continua sendo exibido.\n",
"example": "Membro adicional"
}
}
}
}
}
}
]
},
"SubscriptionBody": {
"type": "object",
"required": [
"customer",
"plan"
],
"properties": {
"customer": {
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "number",
"description": "O ID do cliente na NinePay. Se você ainda não tem o ID do cliente, utilize o endpoint de criação de Cliente para fazer o cadastro e receber o ID."
}
}
},
"plan": {
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "number",
"description": "O ID do plano a que a nova assinatura será vinculada."
}
}
},
"coupon_codes": {
"type": "array",
"items": {
"type": "string",
"example": [
"ABC123",
"DEF456"
]
}
}
}
}
},
"requestBodies": {
"SubscriptionStoreBody": {
"required": true,
"description": "Descreve os dados a serem incluídos no corpo da requisição.\n",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SubscriptionStoreBody"
}
}
}
}
}
},
"tags": [
{
"name": "Assinaturas",
"description": "Assinaturas"
}
],
"x-tagGroups": [
{
"name": "API Calls",
"tags": [
"Pagamentos",
"Clientes",
"Planos",
"Assinaturas",
"Consultas"
]
}
],
"servers": [
{
"url": "https://api.sandbox.cefispay.com.br/api/v1",
"description": "Servidor de Testes (sandbox)"
}
],
"security": [
{
"Bearer": []
}
]
}
```
---
# Atualizar assinatura existente
Source: https://docs.ninepay.com.br/reference/atualizar-assinatura-existente
Atualiza uma assinatura existente com base no ID fornecido. **Nota:** É necessário fornecer o ID da assinatura que deseja atualizar.
# OpenAPI definition
```json
{
"openapi": "3.0.3",
"info": {
"title": "NinePay API",
"version": "1.0",
"x-logo": {
"url": ""
},
"termsOfService": "https://bit.ly/cefispay-contrato",
"contact": {
"name": "NinePay Engineering Team",
"email": "ti@ninepay.com.br"
},
"description": "# Introdução\nBem vindo a referência da **API NinePay**.\nÉ através desta API que você integra o seu sistema ao nosso.\nNossa API é RESTful, e todas suas respostas são em JSON, no endpoint base:\n```\nhttps://payments.cefis.com.br/api/v1/\n```\n\n## Ambientes\nAlém do ambiente de **produção** temos disponível o ambiente **sandbox**\npara a realização de testes de integração. Toda a comunicação com o ambiente sandbox deve ser feita através da url:\n\n```\nhttps://api.sandbox.cefispay.com.br/api/v1/\n```\n\n## Autenticação\nTodas as requisições que requerem autenticação, deverão informar no header `Authorization` o token de api enviado pela nossa equipe, observando sempre o ambiente desejado e no seguinte formato:\n```\nAuthorization: Bearer \n```\n\n## Headers\nRecomendamos que os cabeçalhos da requisições sejam corretamente adicionados para trabalhar com os tipos de dados enviados e recebidos da API:\n - Todas as requisições devem contem o header `Content-Type: application/json`, a menos que o endpoint específico defina diferente\n - Todas as requisições devem contem o header `Accept: application/json`, a menos que o endpoint específico defina diferente\n\n## Respostas\n- Os recursos vêm dentro de `data`: `GET /customers/{id}` responde `{ \"data\": { ... } }`.\n- As criações respondem **201**. `POST /payments` responde `{ \"customer\", \"payment\", \"invoice_url\" }` (o `invoice_url` só no boleto) e `POST /subscriptions` responde `{ \"customer\", \"subscription\" }`.\n- Valores sempre em centavos (inteiro): R$ 50,00 é `5000`.\n\n## Erros\nTodo erro tem o mesmo formato:\n```json\n{\n \"code\": \"VALIDATION_ERROR\",\n \"message\": \"Os dados informados são inválidos.\",\n \"errors\": { \"email\": [\"O campo email é obrigatório.\"] },\n \"timestamp\": \"2026-10-22T12:03:54+00:00\",\n \"request_id\": \"64d62d36-e797-45ed-a9d5-c203bde81032\",\n \"documentation_url\": \"https://docs.ninepay.com.br\",\n \"suggestion\": \"Corrija os campos e tente novamente.\"\n}\n```\n`errors` só vem na validação, com uma **lista** de mensagens por campo. `suggestion` vem quando há uma. Guarde o `request_id` para falar com o suporte.\n\n| `code` | HTTP | Quando |\n| --- | --- | --- |\n| `AUTHENTICATION_ERROR` | 401 | Token ausente ou inválido |\n| `FORBIDDEN_ERROR` | 403 | O recurso não é da sua empresa. Em várias rotas, um id que não existe também responde 403, para não revelar quais ids existem |\n| `COMPANYBLOCKED_ERROR` | 403 | A conta está suspensa |\n| `RESOURCE_NOT_FOUND_ERROR` | 404 | O recurso não existe |\n| `ROUTE_NOT_FOUND_ERROR` | 404 | A rota não existe |\n| `METHOD_NOT_ALLOWED_ERROR` | 405 | O método não vale para a rota (ex.: `PUT /customers` sem o id) |\n| `INVALID_STATE_ERROR` | 400 | O recurso não está num estado que permita a ação (ex.: cancelar um pagamento já pago) |\n| `VALIDATION_ERROR` | 422 | Dados inválidos; veja `errors` |\n| `REFUND_NOT_ALLOWED` | 422 | O pagamento não pode ser reembolsado |\n| `TOO_MANY_ATTEMPTS` | 429 | Muitas requisições; respeite o cabeçalho `Retry-After` |\n| `UNEXPECTED_ERROR` | 500 | Erro nosso; se repetir, fale com o suporte com o `request_id` |\n\n## Paginação\nAs listagens recebem `page` (a partir de 1) e `limit` (itens por página: **10** por padrão, de 1 a **100**). A resposta traz `data` (os itens), `links` e `meta` (`current_page`, `last_page`, `per_page`, `total`).\n\n## Datas\n- Datas de calendário (`due_date`, `next_payment`) vão como `AAAA-MM-DD` na requisição.\n- Nas respostas, os campos de data e hora aparecem em dois formatos: ISO 8601 em UTC (`2026-10-27T03:00:00.000000Z`, em `due_date` e `ref_date` do pagamento) e `AAAA-MM-DD HH:MM:SS` no horário de Brasília (`created_at` e `updated_at`). Leia o campo pelo formato dele.\n\n## Identificadores\nCada recurso tem um `id` numérico e um `uuid`. Use o `id` nas rotas autenticadas e o **`uuid`** em tudo que é público (o link de pagamento, o checkout e o PDF do boleto).\n\n# Hash de cartões\nO hash de um cartão é uma versão criptografada de todos os dados do cartão do cliente, essa é a maneira mais segura de enviar os dados do cartão\ndo seu cliente diretamente para a gente. Abaixo vamos detalhar como ele funciona e como obter um hash a partir dos dados inseridos pelo cliente.\nÉ importante ressaltar que esse fluxo deve ser executado no front-end, seja ele web ou mobile, e que os dados do cartão do cliente nunca devem\nser enviados para o backend, já o hash do cartão pode ser enviado para o backend sem problemas.\n\n## Gerando uma encryption key\nA encryption key consiste basicamente em uma chave pública RSA usada para encriptar os dados do cartão, essa chave só pode ser usada uma vez, então\nsempre que precisar encriptar um novo cartão você precisa gerar uma nova encryption key.\n\nPara gerar uma encryption key é necessário fazer uma requisição ``POST`` para a rota ``/encryption_keys`` da API enviando como parâmetro seu\n``merchant_id``. Ela não usa o token da API (nunca o coloque no front-end): o ``merchant_id`` identifica a sua conta, e um\n``merchant_id`` que não existe responde 401.\n\nA requisição deverá ter esse formato:\n```\ncurl -X POST https://payments.cefis.com.br/api/v1/encryption_keys -H 'Content-Type: application/json' -d '{\"merchant_id\":\"SEU_MERCHANT_ID\"}'\n```\n\nComo resposta você receberá um objeto JSON no seguinte formato:\n```\n{\n \"id\": 1111,\n \"public_key\": \"-----BEGIN PUBLIC KEY-----\\n ... \\n-----END PUBLIC KEY-----\\n\",\n \"ip_address\": \"000.000.000.000\",\n \"created_at\": \"2017-07-03\",\n}\n```\n\n## Encriptando os dados do cartão\nPara encriptar os dados do cartão primeiro você precisa formatá-los de forma correta, para isso crie uma string JSON\ncontendo todos os dados do cartão no seguinte formato:\n\n```\n{\"card_number\":\"1111111111111111\",\"card_holder_name\":\"Jose Silva\",\"card_expiration_date\":\"11/2021\",\"card_cvv\":\"111\"}\n```\n\nEm seguida faça a criptografia RSA dessa string utilizando a chave pública (public_key) gerada no passo anterior, com\npadding do tipo PKCS1.\n\nApós criptografar os dados converta a string resultante para base64 e você terá um resultado parecido com esse:\n\n```\nGprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nO último passo é concatenar o id da sua encryption key (recebido como resposta da requisição anterior) com a string\nem base64 que representa os dados do cartão, da seguinte forma:\n\n``encryption_key_id + \"_\" + base64_encrypted_card``\n\nO resultado será o seu card hash:\n\n```\n1111_GprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nPronto, agora os dados do cartão do cliente já estão em um formato seguro para serem transportados pela rede, podendo\nagora ser enviados para o seu back-end dar sequência ao fluxo. Vale lembrar que cada card hash pode ser usado apenas\numa vez e além disso tem uma validade máxima de 30 minutos após a geração da encryption key. Caso seja necessário utilizar\no cartão mais de uma vez faça uma requisição para a rota de cartões e salve esse cartão vinculado ao usuário que o detém,\nassim você receberá um ID único que poderá ser usado para realizar mais transações com o mesmo cartão.\n"
},
"paths": {
"/subscriptions/{id}": {
"put": {
"summary": "Atualizar assinatura existente",
"tags": [
"Assinaturas"
],
"description": "Atualiza uma assinatura existente com base no ID fornecido. **Nota:** É necessário fornecer o ID da assinatura que deseja atualizar.\n",
"requestBody": {
"$ref": "#/components/requestBodies/SubscriptionBody"
},
"responses": {
"200": {
"description": "Assinatura atualizada com sucesso",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SubscriptionUpdateResponse"
}
}
}
},
"401": {
"$ref": "#/components/responses/401"
},
"422": {
"$ref": "#/components/responses/422"
},
"500": {
"$ref": "#/components/responses/500"
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
]
}
}
},
"components": {
"securitySchemes": {
"Bearer": {
"type": "apiKey",
"in": "header",
"name": "Authorization",
"description": "Todas as requisições que requerem autenticação devem incluir no cabeçalho `Authorization` o token de API enviado pela nossa equipe. O token deve ser fornecido no seguinte formato:\n```\nAuthorization: Bearer \n```"
}
},
"responses": {
"401": {
"description": "Não autenticado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "AUTHENTICATION_ERROR",
"message": "Não autenticado.",
"timestamp": "2026-10-22T12:03:44+00:00",
"request_id": "f2a7e962-6083-4525-816e-f14d4a602e0a",
"documentation_url": "https://docs.ninepay.com.br"
}
}
}
},
"422": {
"description": "Erro na validação dos dados",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "VALIDATION_ERROR",
"message": "Os dados informados são inválidos.",
"errors": {
"email": [
"O campo email é obrigatório."
]
},
"timestamp": "2026-10-22T12:03:54+00:00",
"request_id": "64d62d36-e797-45ed-a9d5-c203bde81032",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Corrija os campos e tente novamente."
}
}
}
},
"500": {
"description": "Erro inesperado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "UNEXPECTED_ERROR",
"message": "Houve um erro inesperado.",
"timestamp": "2026-10-22T12:04:46+00:00",
"request_id": "868443d3-38fd-4c92-8ea8-7cccbbce4308",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Verifique todos os parâmetros da requisição. Se o erro persistir, entre em contato com nossa equipe em ti@ninepay.com.br."
}
}
}
}
},
"schemas": {
"ApiError": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "O código do erro. Ex.: `VALIDATION_ERROR`, `FORBIDDEN_ERROR`, `UNEXPECTED_ERROR`."
},
"message": {
"type": "string",
"description": "A mensagem do erro."
},
"errors": {
"type": "object",
"description": "Os erros de cada campo, quando o `code` é `VALIDATION_ERROR`.",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "A data e hora do erro, em UTC."
},
"request_id": {
"type": "string",
"description": "Um identificador único gerado para esta resposta de erro."
},
"documentation_url": {
"type": "string",
"description": "O endereço desta documentação."
},
"suggestion": {
"type": "string",
"description": "Uma sugestão de como resolver o erro."
}
}
},
"SubscriptionUpdateResponse": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "O ID da assinatura."
},
"uuid": {
"type": "string",
"description": "O UUID da assinatura."
},
"plan_id": {
"type": "string",
"description": "O ID do plano da assinatura."
},
"plan": {
"type": "object",
"description": "O plano da assinatura."
},
"customer_id": {
"type": "string",
"description": "O ID do cliente da assinatura."
},
"customer": {
"type": "object",
"description": "O cliente da assinatura."
},
"method": {
"type": "string",
"description": "O método da assinatura."
},
"card_id": {
"type": "string",
"description": "O ID do cartão de crédito da assinatura."
},
"credit_card": {
"type": "object",
"description": "O cartão de crédito da assinatura."
},
"amount": {
"type": "number",
"description": "O valor recorrente da assinatura."
},
"value": {
"type": "number",
"description": "O valor da assinatura."
},
"last_card_digits": {
"type": "string",
"description": "Os últimos dígitos do cartão da assinatura."
},
"products": {
"type": "array",
"description": "Os produtos da assinatura."
},
"histories": {
"type": "array",
"description": "O histórico da assinatura."
},
"coupons": {
"type": "array",
"description": "Os cupons da assinatura."
},
"status": {
"$ref": "#/components/schemas/SubscriptionStatus"
},
"reason_cancel": {
"type": "string",
"description": "A razão do cancelamento da assinatura."
},
"cancel_type": {
"type": "string",
"description": "O tipo de cancelamento da assinatura."
},
"voluntary_cancel": {
"type": "boolean",
"description": "O cancelamento voluntário da assinatura."
},
"start": {
"type": "string",
"format": "date",
"description": "A data de início da assinatura."
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que a assinatura foi criada."
},
"updated_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que a assinatura foi atualizada."
},
"end": {
"type": "string",
"format": "date",
"description": "A data de término da assinatura."
},
"next_payment": {
"type": "string",
"format": "date-time",
"description": "A data e hora do próximo pagamento da assinatura."
},
"retries": {
"type": "number",
"description": "As tentativas da assinatura."
},
"custom_data": {
"type": "object",
"description": "Os dados personalizados da assinatura."
},
"company": {
"type": "object",
"description": "A empresa da assinatura."
},
"charge_enabled": {
"type": "boolean",
"description": "A habilitação da cobrança da assinatura."
},
"customerContract": {
"type": "object",
"description": "O contrato do cliente da assinatura."
}
}
},
"SubscriptionStatus": {
"type": "string",
"enum": [
"new",
"trial",
"active",
"overdue",
"canceled",
"expired",
"paused"
]
},
"SubscriptionBody": {
"type": "object",
"required": [
"customer",
"plan"
],
"properties": {
"customer": {
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "number",
"description": "O ID do cliente na NinePay. Se você ainda não tem o ID do cliente, utilize o endpoint de criação de Cliente para fazer o cadastro e receber o ID."
}
}
},
"plan": {
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "number",
"description": "O ID do plano a que a nova assinatura será vinculada."
}
}
},
"coupon_codes": {
"type": "array",
"items": {
"type": "string",
"example": [
"ABC123",
"DEF456"
]
}
}
}
}
},
"requestBodies": {
"SubscriptionBody": {
"required": true,
"description": "Descreve os dados a serem incluídos no corpo da requisição.\n",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SubscriptionBody"
}
}
}
}
}
},
"tags": [
{
"name": "Assinaturas",
"description": "Assinaturas"
}
],
"x-tagGroups": [
{
"name": "API Calls",
"tags": [
"Pagamentos",
"Clientes",
"Planos",
"Assinaturas",
"Consultas"
]
}
],
"servers": [
{
"url": "https://api.sandbox.cefispay.com.br/api/v1",
"description": "Servidor de Testes (sandbox)"
}
],
"security": [
{
"Bearer": []
}
]
}
```
---
# Obter detalhes da assinatura
Source: https://docs.ninepay.com.br/reference/obter-detalhes-da-assinatura
Retorna os detalhes de uma assinatura específica, com base no ID fornecido. **Nota:** É necessário fornecer o ID da assinatura para obter os detalhes.
# OpenAPI definition
```json
{
"openapi": "3.0.3",
"info": {
"title": "NinePay API",
"version": "1.0",
"x-logo": {
"url": ""
},
"termsOfService": "https://bit.ly/cefispay-contrato",
"contact": {
"name": "NinePay Engineering Team",
"email": "ti@ninepay.com.br"
},
"description": "# Introdução\nBem vindo a referência da **API NinePay**.\nÉ através desta API que você integra o seu sistema ao nosso.\nNossa API é RESTful, e todas suas respostas são em JSON, no endpoint base:\n```\nhttps://payments.cefis.com.br/api/v1/\n```\n\n## Ambientes\nAlém do ambiente de **produção** temos disponível o ambiente **sandbox**\npara a realização de testes de integração. Toda a comunicação com o ambiente sandbox deve ser feita através da url:\n\n```\nhttps://api.sandbox.cefispay.com.br/api/v1/\n```\n\n## Autenticação\nTodas as requisições que requerem autenticação, deverão informar no header `Authorization` o token de api enviado pela nossa equipe, observando sempre o ambiente desejado e no seguinte formato:\n```\nAuthorization: Bearer \n```\n\n## Headers\nRecomendamos que os cabeçalhos da requisições sejam corretamente adicionados para trabalhar com os tipos de dados enviados e recebidos da API:\n - Todas as requisições devem contem o header `Content-Type: application/json`, a menos que o endpoint específico defina diferente\n - Todas as requisições devem contem o header `Accept: application/json`, a menos que o endpoint específico defina diferente\n\n## Respostas\n- Os recursos vêm dentro de `data`: `GET /customers/{id}` responde `{ \"data\": { ... } }`.\n- As criações respondem **201**. `POST /payments` responde `{ \"customer\", \"payment\", \"invoice_url\" }` (o `invoice_url` só no boleto) e `POST /subscriptions` responde `{ \"customer\", \"subscription\" }`.\n- Valores sempre em centavos (inteiro): R$ 50,00 é `5000`.\n\n## Erros\nTodo erro tem o mesmo formato:\n```json\n{\n \"code\": \"VALIDATION_ERROR\",\n \"message\": \"Os dados informados são inválidos.\",\n \"errors\": { \"email\": [\"O campo email é obrigatório.\"] },\n \"timestamp\": \"2026-10-22T12:03:54+00:00\",\n \"request_id\": \"64d62d36-e797-45ed-a9d5-c203bde81032\",\n \"documentation_url\": \"https://docs.ninepay.com.br\",\n \"suggestion\": \"Corrija os campos e tente novamente.\"\n}\n```\n`errors` só vem na validação, com uma **lista** de mensagens por campo. `suggestion` vem quando há uma. Guarde o `request_id` para falar com o suporte.\n\n| `code` | HTTP | Quando |\n| --- | --- | --- |\n| `AUTHENTICATION_ERROR` | 401 | Token ausente ou inválido |\n| `FORBIDDEN_ERROR` | 403 | O recurso não é da sua empresa. Em várias rotas, um id que não existe também responde 403, para não revelar quais ids existem |\n| `COMPANYBLOCKED_ERROR` | 403 | A conta está suspensa |\n| `RESOURCE_NOT_FOUND_ERROR` | 404 | O recurso não existe |\n| `ROUTE_NOT_FOUND_ERROR` | 404 | A rota não existe |\n| `METHOD_NOT_ALLOWED_ERROR` | 405 | O método não vale para a rota (ex.: `PUT /customers` sem o id) |\n| `INVALID_STATE_ERROR` | 400 | O recurso não está num estado que permita a ação (ex.: cancelar um pagamento já pago) |\n| `VALIDATION_ERROR` | 422 | Dados inválidos; veja `errors` |\n| `REFUND_NOT_ALLOWED` | 422 | O pagamento não pode ser reembolsado |\n| `TOO_MANY_ATTEMPTS` | 429 | Muitas requisições; respeite o cabeçalho `Retry-After` |\n| `UNEXPECTED_ERROR` | 500 | Erro nosso; se repetir, fale com o suporte com o `request_id` |\n\n## Paginação\nAs listagens recebem `page` (a partir de 1) e `limit` (itens por página: **10** por padrão, de 1 a **100**). A resposta traz `data` (os itens), `links` e `meta` (`current_page`, `last_page`, `per_page`, `total`).\n\n## Datas\n- Datas de calendário (`due_date`, `next_payment`) vão como `AAAA-MM-DD` na requisição.\n- Nas respostas, os campos de data e hora aparecem em dois formatos: ISO 8601 em UTC (`2026-10-27T03:00:00.000000Z`, em `due_date` e `ref_date` do pagamento) e `AAAA-MM-DD HH:MM:SS` no horário de Brasília (`created_at` e `updated_at`). Leia o campo pelo formato dele.\n\n## Identificadores\nCada recurso tem um `id` numérico e um `uuid`. Use o `id` nas rotas autenticadas e o **`uuid`** em tudo que é público (o link de pagamento, o checkout e o PDF do boleto).\n\n# Hash de cartões\nO hash de um cartão é uma versão criptografada de todos os dados do cartão do cliente, essa é a maneira mais segura de enviar os dados do cartão\ndo seu cliente diretamente para a gente. Abaixo vamos detalhar como ele funciona e como obter um hash a partir dos dados inseridos pelo cliente.\nÉ importante ressaltar que esse fluxo deve ser executado no front-end, seja ele web ou mobile, e que os dados do cartão do cliente nunca devem\nser enviados para o backend, já o hash do cartão pode ser enviado para o backend sem problemas.\n\n## Gerando uma encryption key\nA encryption key consiste basicamente em uma chave pública RSA usada para encriptar os dados do cartão, essa chave só pode ser usada uma vez, então\nsempre que precisar encriptar um novo cartão você precisa gerar uma nova encryption key.\n\nPara gerar uma encryption key é necessário fazer uma requisição ``POST`` para a rota ``/encryption_keys`` da API enviando como parâmetro seu\n``merchant_id``. Ela não usa o token da API (nunca o coloque no front-end): o ``merchant_id`` identifica a sua conta, e um\n``merchant_id`` que não existe responde 401.\n\nA requisição deverá ter esse formato:\n```\ncurl -X POST https://payments.cefis.com.br/api/v1/encryption_keys -H 'Content-Type: application/json' -d '{\"merchant_id\":\"SEU_MERCHANT_ID\"}'\n```\n\nComo resposta você receberá um objeto JSON no seguinte formato:\n```\n{\n \"id\": 1111,\n \"public_key\": \"-----BEGIN PUBLIC KEY-----\\n ... \\n-----END PUBLIC KEY-----\\n\",\n \"ip_address\": \"000.000.000.000\",\n \"created_at\": \"2017-07-03\",\n}\n```\n\n## Encriptando os dados do cartão\nPara encriptar os dados do cartão primeiro você precisa formatá-los de forma correta, para isso crie uma string JSON\ncontendo todos os dados do cartão no seguinte formato:\n\n```\n{\"card_number\":\"1111111111111111\",\"card_holder_name\":\"Jose Silva\",\"card_expiration_date\":\"11/2021\",\"card_cvv\":\"111\"}\n```\n\nEm seguida faça a criptografia RSA dessa string utilizando a chave pública (public_key) gerada no passo anterior, com\npadding do tipo PKCS1.\n\nApós criptografar os dados converta a string resultante para base64 e você terá um resultado parecido com esse:\n\n```\nGprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nO último passo é concatenar o id da sua encryption key (recebido como resposta da requisição anterior) com a string\nem base64 que representa os dados do cartão, da seguinte forma:\n\n``encryption_key_id + \"_\" + base64_encrypted_card``\n\nO resultado será o seu card hash:\n\n```\n1111_GprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nPronto, agora os dados do cartão do cliente já estão em um formato seguro para serem transportados pela rede, podendo\nagora ser enviados para o seu back-end dar sequência ao fluxo. Vale lembrar que cada card hash pode ser usado apenas\numa vez e além disso tem uma validade máxima de 30 minutos após a geração da encryption key. Caso seja necessário utilizar\no cartão mais de uma vez faça uma requisição para a rota de cartões e salve esse cartão vinculado ao usuário que o detém,\nassim você receberá um ID único que poderá ser usado para realizar mais transações com o mesmo cartão.\n"
},
"paths": {
"/subscriptions/{id}": {
"get": {
"summary": "Obter detalhes da assinatura",
"tags": [
"Assinaturas"
],
"description": "Retorna os detalhes de uma assinatura específica, com base no ID fornecido. **Nota:** É necessário fornecer o ID da assinatura para obter os detalhes.\n",
"responses": {
"200": {
"description": "Detalhes da assinatura retornados com sucesso",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SubscriptionDetailsResponse"
}
}
}
},
"401": {
"$ref": "#/components/responses/401"
},
"422": {
"$ref": "#/components/responses/422"
},
"500": {
"$ref": "#/components/responses/500"
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
]
}
}
},
"components": {
"securitySchemes": {
"Bearer": {
"type": "apiKey",
"in": "header",
"name": "Authorization",
"description": "Todas as requisições que requerem autenticação devem incluir no cabeçalho `Authorization` o token de API enviado pela nossa equipe. O token deve ser fornecido no seguinte formato:\n```\nAuthorization: Bearer \n```"
}
},
"responses": {
"401": {
"description": "Não autenticado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "AUTHENTICATION_ERROR",
"message": "Não autenticado.",
"timestamp": "2026-10-22T12:03:44+00:00",
"request_id": "f2a7e962-6083-4525-816e-f14d4a602e0a",
"documentation_url": "https://docs.ninepay.com.br"
}
}
}
},
"422": {
"description": "Erro na validação dos dados",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "VALIDATION_ERROR",
"message": "Os dados informados são inválidos.",
"errors": {
"email": [
"O campo email é obrigatório."
]
},
"timestamp": "2026-10-22T12:03:54+00:00",
"request_id": "64d62d36-e797-45ed-a9d5-c203bde81032",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Corrija os campos e tente novamente."
}
}
}
},
"500": {
"description": "Erro inesperado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "UNEXPECTED_ERROR",
"message": "Houve um erro inesperado.",
"timestamp": "2026-10-22T12:04:46+00:00",
"request_id": "868443d3-38fd-4c92-8ea8-7cccbbce4308",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Verifique todos os parâmetros da requisição. Se o erro persistir, entre em contato com nossa equipe em ti@ninepay.com.br."
}
}
}
}
},
"schemas": {
"ApiError": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "O código do erro. Ex.: `VALIDATION_ERROR`, `FORBIDDEN_ERROR`, `UNEXPECTED_ERROR`."
},
"message": {
"type": "string",
"description": "A mensagem do erro."
},
"errors": {
"type": "object",
"description": "Os erros de cada campo, quando o `code` é `VALIDATION_ERROR`.",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "A data e hora do erro, em UTC."
},
"request_id": {
"type": "string",
"description": "Um identificador único gerado para esta resposta de erro."
},
"documentation_url": {
"type": "string",
"description": "O endereço desta documentação."
},
"suggestion": {
"type": "string",
"description": "Uma sugestão de como resolver o erro."
}
}
},
"SubscriptionDetailsResponse": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "O ID da assinatura."
},
"uuid": {
"type": "string",
"description": "O UUID da assinatura."
},
"plan_id": {
"type": "string",
"description": "O ID do plano da assinatura."
},
"plan": {
"type": "object",
"description": "O plano da assinatura."
},
"customer_id": {
"type": "string",
"description": "O ID do cliente da assinatura."
},
"customer": {
"type": "object",
"description": "O cliente da assinatura."
},
"method": {
"type": "string",
"description": "O método da assinatura."
},
"card_id": {
"type": "string",
"description": "O ID do cartão de crédito da assinatura."
},
"credit_card": {
"type": "object",
"description": "O cartão de crédito da assinatura."
},
"amount": {
"type": "number",
"description": "O valor recorrente da assinatura."
},
"value": {
"type": "number",
"description": "O valor da assinatura."
},
"last_card_digits": {
"type": "string",
"description": "Os últimos dígitos do cartão da assinatura."
},
"products": {
"type": "array",
"description": "Os produtos da assinatura."
},
"histories": {
"type": "array",
"description": "O histórico da assinatura."
},
"coupons": {
"type": "array",
"description": "Os cupons da assinatura."
},
"status": {
"$ref": "#/components/schemas/SubscriptionStatus"
},
"reason_cancel": {
"type": "string",
"description": "A razão do cancelamento da assinatura."
},
"cancel_type": {
"type": "string",
"description": "O tipo de cancelamento da assinatura."
},
"voluntary_cancel": {
"type": "boolean",
"description": "O cancelamento voluntário da assinatura."
},
"start": {
"type": "string",
"format": "date",
"description": "A data de início da assinatura."
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que a assinatura foi criada."
},
"updated_at": {
"type": "string",
"format": "date-time",
"description": "A data e hora em que a assinatura foi atualizada."
},
"end": {
"type": "string",
"format": "date",
"description": "A data de término da assinatura."
},
"next_payment": {
"type": "string",
"format": "date-time",
"description": "A data e hora do próximo pagamento da assinatura."
},
"retries": {
"type": "number",
"description": "As tentativas da assinatura."
},
"custom_data": {
"type": "object",
"description": "Os dados personalizados da assinatura."
},
"company": {
"type": "object",
"description": "A empresa da assinatura."
},
"charge_enabled": {
"type": "boolean",
"description": "A habilitação da cobrança da assinatura."
},
"customerContract": {
"type": "object",
"description": "O contrato do cliente da assinatura."
}
}
},
"SubscriptionStatus": {
"type": "string",
"enum": [
"new",
"trial",
"active",
"overdue",
"canceled",
"expired",
"paused"
]
}
}
},
"tags": [
{
"name": "Assinaturas",
"description": "Assinaturas"
}
],
"x-tagGroups": [
{
"name": "API Calls",
"tags": [
"Pagamentos",
"Clientes",
"Planos",
"Assinaturas",
"Consultas"
]
}
],
"servers": [
{
"url": "https://api.sandbox.cefispay.com.br/api/v1",
"description": "Servidor de Testes (sandbox)"
}
],
"security": [
{
"Bearer": []
}
]
}
```
---
# Cancelar uma assinatura
Source: https://docs.ninepay.com.br/reference/cancelar-uma-assinatura
Cancela uma assinatura. Assinaturas canceladas não enviam mais cobranças aos clientes e não geram pagamentos futuros.
# OpenAPI definition
```json
{
"openapi": "3.0.3",
"info": {
"title": "NinePay API",
"version": "1.0",
"x-logo": {
"url": ""
},
"termsOfService": "https://bit.ly/cefispay-contrato",
"contact": {
"name": "NinePay Engineering Team",
"email": "ti@ninepay.com.br"
},
"description": "# Introdução\nBem vindo a referência da **API NinePay**.\nÉ através desta API que você integra o seu sistema ao nosso.\nNossa API é RESTful, e todas suas respostas são em JSON, no endpoint base:\n```\nhttps://payments.cefis.com.br/api/v1/\n```\n\n## Ambientes\nAlém do ambiente de **produção** temos disponível o ambiente **sandbox**\npara a realização de testes de integração. Toda a comunicação com o ambiente sandbox deve ser feita através da url:\n\n```\nhttps://api.sandbox.cefispay.com.br/api/v1/\n```\n\n## Autenticação\nTodas as requisições que requerem autenticação, deverão informar no header `Authorization` o token de api enviado pela nossa equipe, observando sempre o ambiente desejado e no seguinte formato:\n```\nAuthorization: Bearer \n```\n\n## Headers\nRecomendamos que os cabeçalhos da requisições sejam corretamente adicionados para trabalhar com os tipos de dados enviados e recebidos da API:\n - Todas as requisições devem contem o header `Content-Type: application/json`, a menos que o endpoint específico defina diferente\n - Todas as requisições devem contem o header `Accept: application/json`, a menos que o endpoint específico defina diferente\n\n## Respostas\n- Os recursos vêm dentro de `data`: `GET /customers/{id}` responde `{ \"data\": { ... } }`.\n- As criações respondem **201**. `POST /payments` responde `{ \"customer\", \"payment\", \"invoice_url\" }` (o `invoice_url` só no boleto) e `POST /subscriptions` responde `{ \"customer\", \"subscription\" }`.\n- Valores sempre em centavos (inteiro): R$ 50,00 é `5000`.\n\n## Erros\nTodo erro tem o mesmo formato:\n```json\n{\n \"code\": \"VALIDATION_ERROR\",\n \"message\": \"Os dados informados são inválidos.\",\n \"errors\": { \"email\": [\"O campo email é obrigatório.\"] },\n \"timestamp\": \"2026-10-22T12:03:54+00:00\",\n \"request_id\": \"64d62d36-e797-45ed-a9d5-c203bde81032\",\n \"documentation_url\": \"https://docs.ninepay.com.br\",\n \"suggestion\": \"Corrija os campos e tente novamente.\"\n}\n```\n`errors` só vem na validação, com uma **lista** de mensagens por campo. `suggestion` vem quando há uma. Guarde o `request_id` para falar com o suporte.\n\n| `code` | HTTP | Quando |\n| --- | --- | --- |\n| `AUTHENTICATION_ERROR` | 401 | Token ausente ou inválido |\n| `FORBIDDEN_ERROR` | 403 | O recurso não é da sua empresa. Em várias rotas, um id que não existe também responde 403, para não revelar quais ids existem |\n| `COMPANYBLOCKED_ERROR` | 403 | A conta está suspensa |\n| `RESOURCE_NOT_FOUND_ERROR` | 404 | O recurso não existe |\n| `ROUTE_NOT_FOUND_ERROR` | 404 | A rota não existe |\n| `METHOD_NOT_ALLOWED_ERROR` | 405 | O método não vale para a rota (ex.: `PUT /customers` sem o id) |\n| `INVALID_STATE_ERROR` | 400 | O recurso não está num estado que permita a ação (ex.: cancelar um pagamento já pago) |\n| `VALIDATION_ERROR` | 422 | Dados inválidos; veja `errors` |\n| `REFUND_NOT_ALLOWED` | 422 | O pagamento não pode ser reembolsado |\n| `TOO_MANY_ATTEMPTS` | 429 | Muitas requisições; respeite o cabeçalho `Retry-After` |\n| `UNEXPECTED_ERROR` | 500 | Erro nosso; se repetir, fale com o suporte com o `request_id` |\n\n## Paginação\nAs listagens recebem `page` (a partir de 1) e `limit` (itens por página: **10** por padrão, de 1 a **100**). A resposta traz `data` (os itens), `links` e `meta` (`current_page`, `last_page`, `per_page`, `total`).\n\n## Datas\n- Datas de calendário (`due_date`, `next_payment`) vão como `AAAA-MM-DD` na requisição.\n- Nas respostas, os campos de data e hora aparecem em dois formatos: ISO 8601 em UTC (`2026-10-27T03:00:00.000000Z`, em `due_date` e `ref_date` do pagamento) e `AAAA-MM-DD HH:MM:SS` no horário de Brasília (`created_at` e `updated_at`). Leia o campo pelo formato dele.\n\n## Identificadores\nCada recurso tem um `id` numérico e um `uuid`. Use o `id` nas rotas autenticadas e o **`uuid`** em tudo que é público (o link de pagamento, o checkout e o PDF do boleto).\n\n# Hash de cartões\nO hash de um cartão é uma versão criptografada de todos os dados do cartão do cliente, essa é a maneira mais segura de enviar os dados do cartão\ndo seu cliente diretamente para a gente. Abaixo vamos detalhar como ele funciona e como obter um hash a partir dos dados inseridos pelo cliente.\nÉ importante ressaltar que esse fluxo deve ser executado no front-end, seja ele web ou mobile, e que os dados do cartão do cliente nunca devem\nser enviados para o backend, já o hash do cartão pode ser enviado para o backend sem problemas.\n\n## Gerando uma encryption key\nA encryption key consiste basicamente em uma chave pública RSA usada para encriptar os dados do cartão, essa chave só pode ser usada uma vez, então\nsempre que precisar encriptar um novo cartão você precisa gerar uma nova encryption key.\n\nPara gerar uma encryption key é necessário fazer uma requisição ``POST`` para a rota ``/encryption_keys`` da API enviando como parâmetro seu\n``merchant_id``. Ela não usa o token da API (nunca o coloque no front-end): o ``merchant_id`` identifica a sua conta, e um\n``merchant_id`` que não existe responde 401.\n\nA requisição deverá ter esse formato:\n```\ncurl -X POST https://payments.cefis.com.br/api/v1/encryption_keys -H 'Content-Type: application/json' -d '{\"merchant_id\":\"SEU_MERCHANT_ID\"}'\n```\n\nComo resposta você receberá um objeto JSON no seguinte formato:\n```\n{\n \"id\": 1111,\n \"public_key\": \"-----BEGIN PUBLIC KEY-----\\n ... \\n-----END PUBLIC KEY-----\\n\",\n \"ip_address\": \"000.000.000.000\",\n \"created_at\": \"2017-07-03\",\n}\n```\n\n## Encriptando os dados do cartão\nPara encriptar os dados do cartão primeiro você precisa formatá-los de forma correta, para isso crie uma string JSON\ncontendo todos os dados do cartão no seguinte formato:\n\n```\n{\"card_number\":\"1111111111111111\",\"card_holder_name\":\"Jose Silva\",\"card_expiration_date\":\"11/2021\",\"card_cvv\":\"111\"}\n```\n\nEm seguida faça a criptografia RSA dessa string utilizando a chave pública (public_key) gerada no passo anterior, com\npadding do tipo PKCS1.\n\nApós criptografar os dados converta a string resultante para base64 e você terá um resultado parecido com esse:\n\n```\nGprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nO último passo é concatenar o id da sua encryption key (recebido como resposta da requisição anterior) com a string\nem base64 que representa os dados do cartão, da seguinte forma:\n\n``encryption_key_id + \"_\" + base64_encrypted_card``\n\nO resultado será o seu card hash:\n\n```\n1111_GprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nPronto, agora os dados do cartão do cliente já estão em um formato seguro para serem transportados pela rede, podendo\nagora ser enviados para o seu back-end dar sequência ao fluxo. Vale lembrar que cada card hash pode ser usado apenas\numa vez e além disso tem uma validade máxima de 30 minutos após a geração da encryption key. Caso seja necessário utilizar\no cartão mais de uma vez faça uma requisição para a rota de cartões e salve esse cartão vinculado ao usuário que o detém,\nassim você receberá um ID único que poderá ser usado para realizar mais transações com o mesmo cartão.\n"
},
"paths": {
"/subscriptions/{id}": {
"post": {
"summary": "Cancelar uma assinatura",
"tags": [
"Assinaturas"
],
"description": "Cancela uma assinatura. Assinaturas canceladas não enviam mais cobranças aos clientes e não geram pagamentos futuros.\n",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"description": "O id da assinatura a ser cancelada",
"example": 42
}
}
}
}
}
},
"responses": {
"200": {
"description": "Assinatura criada com sucesso",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SubscriptionStoreResponse"
}
}
}
},
"401": {
"$ref": "#/components/responses/401"
},
"422": {
"$ref": "#/components/responses/422"
},
"500": {
"$ref": "#/components/responses/500"
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
]
}
}
},
"components": {
"securitySchemes": {
"Bearer": {
"type": "apiKey",
"in": "header",
"name": "Authorization",
"description": "Todas as requisições que requerem autenticação devem incluir no cabeçalho `Authorization` o token de API enviado pela nossa equipe. O token deve ser fornecido no seguinte formato:\n```\nAuthorization: Bearer \n```"
}
},
"responses": {
"401": {
"description": "Não autenticado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "AUTHENTICATION_ERROR",
"message": "Não autenticado.",
"timestamp": "2026-10-22T12:03:44+00:00",
"request_id": "f2a7e962-6083-4525-816e-f14d4a602e0a",
"documentation_url": "https://docs.ninepay.com.br"
}
}
}
},
"422": {
"description": "Erro na validação dos dados",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "VALIDATION_ERROR",
"message": "Os dados informados são inválidos.",
"errors": {
"email": [
"O campo email é obrigatório."
]
},
"timestamp": "2026-10-22T12:03:54+00:00",
"request_id": "64d62d36-e797-45ed-a9d5-c203bde81032",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Corrija os campos e tente novamente."
}
}
}
},
"500": {
"description": "Erro inesperado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "UNEXPECTED_ERROR",
"message": "Houve um erro inesperado.",
"timestamp": "2026-10-22T12:04:46+00:00",
"request_id": "868443d3-38fd-4c92-8ea8-7cccbbce4308",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Verifique todos os parâmetros da requisição. Se o erro persistir, entre em contato com nossa equipe em ti@ninepay.com.br."
}
}
}
}
},
"schemas": {
"ApiError": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "O código do erro. Ex.: `VALIDATION_ERROR`, `FORBIDDEN_ERROR`, `UNEXPECTED_ERROR`."
},
"message": {
"type": "string",
"description": "A mensagem do erro."
},
"errors": {
"type": "object",
"description": "Os erros de cada campo, quando o `code` é `VALIDATION_ERROR`.",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "A data e hora do erro, em UTC."
},
"request_id": {
"type": "string",
"description": "Um identificador único gerado para esta resposta de erro."
},
"documentation_url": {
"type": "string",
"description": "O endereço desta documentação."
},
"suggestion": {
"type": "string",
"description": "Uma sugestão de como resolver o erro."
}
}
},
"SubscriptionStoreResponse": {
"type": "object",
"properties": {
"subscription": {
"$ref": "#/components/schemas/Subscription"
},
"customer": {
"$ref": "#/components/schemas/Customer"
}
}
},
"Customer": {
"type": "object",
"required": [
"id",
"name",
"email",
"cpf",
"cnpj"
],
"properties": {
"id": {
"description": "O id do cliente na NinePay. Obrigatório se os demais dados do usuário não forem informados",
"type": "integer",
"example": 42,
"readOnly": true
},
"name": {
"description": "O nome do cliente. Obrigatório se o `id` não for informado",
"type": "string",
"example": "Jhon Doe"
},
"email": {
"description": "O email do cliente. Obrigatório se o `id` não for informado",
"type": "string",
"example": "jhon@doe.com"
},
"cpf": {
"description": "O cpf do cliente. Obrigatório se o `id` ou o `cnpj` não forem informados",
"type": "string",
"example": "833.828.600-15"
},
"cnpj": {
"description": "O cnpj do cliente. Obrigatório se o `id` ou o `cpf` não forem informados",
"type": "string",
"example": "95.135.209/0001-79"
},
"phone": {
"description": "O telefone celular do cliente, com DDD. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": "(11) 11111-1111"
},
"cep": {
"description": "O CEP do cliente. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": "01423-910"
},
"address": {
"description": "O endereço do cliente",
"type": "string",
"example": "Rua José Maria Lisboa"
},
"number": {
"description": "O número do endereço do cliente. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": 42
},
"district": {
"description": "O bairro do cliente",
"type": "string",
"example": "Jardim Paulista"
},
"city": {
"description": "A cidade do cliente",
"type": "string",
"example": "São Paulo"
},
"state": {
"description": "O estado do cliente",
"type": "string",
"example": "SP"
},
"country": {
"description": "O código do país do cliente, no formato Alpha 2 de acordo com a [ISO 3166](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes).",
"type": "string",
"example": "BR"
}
}
},
"Subscription": {
"type": "object",
"properties": {
"id": {
"description": "O id da assinatura.",
"type": "integer",
"example": 42,
"readOnly": true
},
"uuid": {
"description": "O id publico da assinatura. Esse id pode ser usado para levar o cliente a página de checkout para pagamento.",
"type": "string",
"format": "uuid",
"example": "8b2cad02-06f0-42be-84ac-101b23a1bb0d"
},
"amount": {
"description": "O valor da assinatura em centavos.",
"type": "number",
"example": 2500
},
"plan_id": {
"description": "O id do plano.",
"type": "number",
"example": 2500
},
"status": {
"description": "O status da assinatura.",
"$ref": "#/components/schemas/SubscriptionStatus",
"example": "credit"
},
"created_at": {
"description": "Data de criação.",
"type": "string",
"format": "date-time",
"example": "2017-07-21 05:20:00"
}
}
},
"SubscriptionStatus": {
"type": "string",
"enum": [
"new",
"trial",
"active",
"overdue",
"canceled",
"expired",
"paused"
]
}
}
},
"tags": [
{
"name": "Assinaturas",
"description": "Assinaturas"
}
],
"x-tagGroups": [
{
"name": "API Calls",
"tags": [
"Pagamentos",
"Clientes",
"Planos",
"Assinaturas",
"Consultas"
]
}
],
"servers": [
{
"url": "https://api.sandbox.cefispay.com.br/api/v1",
"description": "Servidor de Testes (sandbox)"
}
],
"security": [
{
"Bearer": []
}
]
}
```
---
# Listar os produtos da assinatura
Source: https://docs.ninepay.com.br/reference/listar-os-produtos-da-assinatura
Lista os produtos de uma assinatura. Os produtos são cobrados junto do plano, e a soma deles com o valor do plano é o `amount` da assinatura.
# OpenAPI definition
```json
{
"openapi": "3.0.3",
"info": {
"title": "NinePay API",
"version": "1.0",
"x-logo": {
"url": ""
},
"termsOfService": "https://bit.ly/cefispay-contrato",
"contact": {
"name": "NinePay Engineering Team",
"email": "ti@ninepay.com.br"
},
"description": "# Introdução\nBem vindo a referência da **API NinePay**.\nÉ através desta API que você integra o seu sistema ao nosso.\nNossa API é RESTful, e todas suas respostas são em JSON, no endpoint base:\n```\nhttps://payments.cefis.com.br/api/v1/\n```\n\n## Ambientes\nAlém do ambiente de **produção** temos disponível o ambiente **sandbox**\npara a realização de testes de integração. Toda a comunicação com o ambiente sandbox deve ser feita através da url:\n\n```\nhttps://api.sandbox.cefispay.com.br/api/v1/\n```\n\n## Autenticação\nTodas as requisições que requerem autenticação, deverão informar no header `Authorization` o token de api enviado pela nossa equipe, observando sempre o ambiente desejado e no seguinte formato:\n```\nAuthorization: Bearer \n```\n\n## Headers\nRecomendamos que os cabeçalhos da requisições sejam corretamente adicionados para trabalhar com os tipos de dados enviados e recebidos da API:\n - Todas as requisições devem contem o header `Content-Type: application/json`, a menos que o endpoint específico defina diferente\n - Todas as requisições devem contem o header `Accept: application/json`, a menos que o endpoint específico defina diferente\n\n## Respostas\n- Os recursos vêm dentro de `data`: `GET /customers/{id}` responde `{ \"data\": { ... } }`.\n- As criações respondem **201**. `POST /payments` responde `{ \"customer\", \"payment\", \"invoice_url\" }` (o `invoice_url` só no boleto) e `POST /subscriptions` responde `{ \"customer\", \"subscription\" }`.\n- Valores sempre em centavos (inteiro): R$ 50,00 é `5000`.\n\n## Erros\nTodo erro tem o mesmo formato:\n```json\n{\n \"code\": \"VALIDATION_ERROR\",\n \"message\": \"Os dados informados são inválidos.\",\n \"errors\": { \"email\": [\"O campo email é obrigatório.\"] },\n \"timestamp\": \"2026-10-22T12:03:54+00:00\",\n \"request_id\": \"64d62d36-e797-45ed-a9d5-c203bde81032\",\n \"documentation_url\": \"https://docs.ninepay.com.br\",\n \"suggestion\": \"Corrija os campos e tente novamente.\"\n}\n```\n`errors` só vem na validação, com uma **lista** de mensagens por campo. `suggestion` vem quando há uma. Guarde o `request_id` para falar com o suporte.\n\n| `code` | HTTP | Quando |\n| --- | --- | --- |\n| `AUTHENTICATION_ERROR` | 401 | Token ausente ou inválido |\n| `FORBIDDEN_ERROR` | 403 | O recurso não é da sua empresa. Em várias rotas, um id que não existe também responde 403, para não revelar quais ids existem |\n| `COMPANYBLOCKED_ERROR` | 403 | A conta está suspensa |\n| `RESOURCE_NOT_FOUND_ERROR` | 404 | O recurso não existe |\n| `ROUTE_NOT_FOUND_ERROR` | 404 | A rota não existe |\n| `METHOD_NOT_ALLOWED_ERROR` | 405 | O método não vale para a rota (ex.: `PUT /customers` sem o id) |\n| `INVALID_STATE_ERROR` | 400 | O recurso não está num estado que permita a ação (ex.: cancelar um pagamento já pago) |\n| `VALIDATION_ERROR` | 422 | Dados inválidos; veja `errors` |\n| `REFUND_NOT_ALLOWED` | 422 | O pagamento não pode ser reembolsado |\n| `TOO_MANY_ATTEMPTS` | 429 | Muitas requisições; respeite o cabeçalho `Retry-After` |\n| `UNEXPECTED_ERROR` | 500 | Erro nosso; se repetir, fale com o suporte com o `request_id` |\n\n## Paginação\nAs listagens recebem `page` (a partir de 1) e `limit` (itens por página: **10** por padrão, de 1 a **100**). A resposta traz `data` (os itens), `links` e `meta` (`current_page`, `last_page`, `per_page`, `total`).\n\n## Datas\n- Datas de calendário (`due_date`, `next_payment`) vão como `AAAA-MM-DD` na requisição.\n- Nas respostas, os campos de data e hora aparecem em dois formatos: ISO 8601 em UTC (`2026-10-27T03:00:00.000000Z`, em `due_date` e `ref_date` do pagamento) e `AAAA-MM-DD HH:MM:SS` no horário de Brasília (`created_at` e `updated_at`). Leia o campo pelo formato dele.\n\n## Identificadores\nCada recurso tem um `id` numérico e um `uuid`. Use o `id` nas rotas autenticadas e o **`uuid`** em tudo que é público (o link de pagamento, o checkout e o PDF do boleto).\n\n# Hash de cartões\nO hash de um cartão é uma versão criptografada de todos os dados do cartão do cliente, essa é a maneira mais segura de enviar os dados do cartão\ndo seu cliente diretamente para a gente. Abaixo vamos detalhar como ele funciona e como obter um hash a partir dos dados inseridos pelo cliente.\nÉ importante ressaltar que esse fluxo deve ser executado no front-end, seja ele web ou mobile, e que os dados do cartão do cliente nunca devem\nser enviados para o backend, já o hash do cartão pode ser enviado para o backend sem problemas.\n\n## Gerando uma encryption key\nA encryption key consiste basicamente em uma chave pública RSA usada para encriptar os dados do cartão, essa chave só pode ser usada uma vez, então\nsempre que precisar encriptar um novo cartão você precisa gerar uma nova encryption key.\n\nPara gerar uma encryption key é necessário fazer uma requisição ``POST`` para a rota ``/encryption_keys`` da API enviando como parâmetro seu\n``merchant_id``. Ela não usa o token da API (nunca o coloque no front-end): o ``merchant_id`` identifica a sua conta, e um\n``merchant_id`` que não existe responde 401.\n\nA requisição deverá ter esse formato:\n```\ncurl -X POST https://payments.cefis.com.br/api/v1/encryption_keys -H 'Content-Type: application/json' -d '{\"merchant_id\":\"SEU_MERCHANT_ID\"}'\n```\n\nComo resposta você receberá um objeto JSON no seguinte formato:\n```\n{\n \"id\": 1111,\n \"public_key\": \"-----BEGIN PUBLIC KEY-----\\n ... \\n-----END PUBLIC KEY-----\\n\",\n \"ip_address\": \"000.000.000.000\",\n \"created_at\": \"2017-07-03\",\n}\n```\n\n## Encriptando os dados do cartão\nPara encriptar os dados do cartão primeiro você precisa formatá-los de forma correta, para isso crie uma string JSON\ncontendo todos os dados do cartão no seguinte formato:\n\n```\n{\"card_number\":\"1111111111111111\",\"card_holder_name\":\"Jose Silva\",\"card_expiration_date\":\"11/2021\",\"card_cvv\":\"111\"}\n```\n\nEm seguida faça a criptografia RSA dessa string utilizando a chave pública (public_key) gerada no passo anterior, com\npadding do tipo PKCS1.\n\nApós criptografar os dados converta a string resultante para base64 e você terá um resultado parecido com esse:\n\n```\nGprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nO último passo é concatenar o id da sua encryption key (recebido como resposta da requisição anterior) com a string\nem base64 que representa os dados do cartão, da seguinte forma:\n\n``encryption_key_id + \"_\" + base64_encrypted_card``\n\nO resultado será o seu card hash:\n\n```\n1111_GprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nPronto, agora os dados do cartão do cliente já estão em um formato seguro para serem transportados pela rede, podendo\nagora ser enviados para o seu back-end dar sequência ao fluxo. Vale lembrar que cada card hash pode ser usado apenas\numa vez e além disso tem uma validade máxima de 30 minutos após a geração da encryption key. Caso seja necessário utilizar\no cartão mais de uma vez faça uma requisição para a rota de cartões e salve esse cartão vinculado ao usuário que o detém,\nassim você receberá um ID único que poderá ser usado para realizar mais transações com o mesmo cartão.\n"
},
"paths": {
"/subscriptions/{id}/products": {
"get": {
"summary": "Listar os produtos da assinatura",
"tags": [
"Assinaturas"
],
"description": "Lista os produtos de uma assinatura. Os produtos são cobrados junto do plano, e a soma deles com o valor do plano é o `amount` da assinatura.\n",
"responses": {
"200": {
"description": "Produtos da assinatura retornados com sucesso",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SubscriptionProductsListResponse"
}
}
}
},
"401": {
"$ref": "#/components/responses/401"
},
"422": {
"$ref": "#/components/responses/422"
},
"500": {
"$ref": "#/components/responses/500"
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
]
}
}
},
"components": {
"securitySchemes": {
"Bearer": {
"type": "apiKey",
"in": "header",
"name": "Authorization",
"description": "Todas as requisições que requerem autenticação devem incluir no cabeçalho `Authorization` o token de API enviado pela nossa equipe. O token deve ser fornecido no seguinte formato:\n```\nAuthorization: Bearer \n```"
}
},
"responses": {
"401": {
"description": "Não autenticado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "AUTHENTICATION_ERROR",
"message": "Não autenticado.",
"timestamp": "2026-10-22T12:03:44+00:00",
"request_id": "f2a7e962-6083-4525-816e-f14d4a602e0a",
"documentation_url": "https://docs.ninepay.com.br"
}
}
}
},
"422": {
"description": "Erro na validação dos dados",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "VALIDATION_ERROR",
"message": "Os dados informados são inválidos.",
"errors": {
"email": [
"O campo email é obrigatório."
]
},
"timestamp": "2026-10-22T12:03:54+00:00",
"request_id": "64d62d36-e797-45ed-a9d5-c203bde81032",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Corrija os campos e tente novamente."
}
}
}
},
"500": {
"description": "Erro inesperado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "UNEXPECTED_ERROR",
"message": "Houve um erro inesperado.",
"timestamp": "2026-10-22T12:04:46+00:00",
"request_id": "868443d3-38fd-4c92-8ea8-7cccbbce4308",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Verifique todos os parâmetros da requisição. Se o erro persistir, entre em contato com nossa equipe em ti@ninepay.com.br."
}
}
}
}
},
"schemas": {
"ApiError": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "O código do erro. Ex.: `VALIDATION_ERROR`, `FORBIDDEN_ERROR`, `UNEXPECTED_ERROR`."
},
"message": {
"type": "string",
"description": "A mensagem do erro."
},
"errors": {
"type": "object",
"description": "Os erros de cada campo, quando o `code` é `VALIDATION_ERROR`.",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "A data e hora do erro, em UTC."
},
"request_id": {
"type": "string",
"description": "Um identificador único gerado para esta resposta de erro."
},
"documentation_url": {
"type": "string",
"description": "O endereço desta documentação."
},
"suggestion": {
"type": "string",
"description": "Uma sugestão de como resolver o erro."
}
}
},
"SubscriptionProductsListResponse": {
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/SubscriptionProduct"
}
}
}
},
"SubscriptionProduct": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"description": "O ID do produto na NinePay."
},
"subscription_id": {
"type": "integer",
"description": "O ID da assinatura a que o produto pertence."
},
"identifier": {
"type": "string",
"description": "A chave do produto, pela qual ele é removido.",
"example": "team_user"
},
"name": {
"type": "string",
"nullable": true,
"description": "O que o cliente lê na cobrança. Quando nulo, o `identifier` é exibido.\n",
"example": "Membro adicional"
},
"value": {
"type": "integer",
"description": "O valor do produto, em centavos.",
"example": 1290
},
"created_at": {
"type": "string",
"description": "A data de criação do produto."
},
"updated_at": {
"type": "string",
"description": "A data da última atualização do produto."
}
}
}
}
},
"tags": [
{
"name": "Assinaturas",
"description": "Assinaturas"
}
],
"x-tagGroups": [
{
"name": "API Calls",
"tags": [
"Pagamentos",
"Clientes",
"Planos",
"Assinaturas",
"Consultas"
]
}
],
"servers": [
{
"url": "https://api.sandbox.cefispay.com.br/api/v1",
"description": "Servidor de Testes (sandbox)"
}
],
"security": [
{
"Bearer": []
}
]
}
```
---
# Anexar produtos à assinatura
Source: https://docs.ninepay.com.br/reference/anexar-produtos-a-assinatura
Anexa produtos a uma assinatura já criada. Eles passam a ser cobrados junto do plano a partir da cobrança seguinte. Para que os produtos entrem já na primeira cobrança, envie-os no campo `products` na criação da assinatura.
# OpenAPI definition
```json
{
"openapi": "3.0.3",
"info": {
"title": "NinePay API",
"version": "1.0",
"x-logo": {
"url": ""
},
"termsOfService": "https://bit.ly/cefispay-contrato",
"contact": {
"name": "NinePay Engineering Team",
"email": "ti@ninepay.com.br"
},
"description": "# Introdução\nBem vindo a referência da **API NinePay**.\nÉ através desta API que você integra o seu sistema ao nosso.\nNossa API é RESTful, e todas suas respostas são em JSON, no endpoint base:\n```\nhttps://payments.cefis.com.br/api/v1/\n```\n\n## Ambientes\nAlém do ambiente de **produção** temos disponível o ambiente **sandbox**\npara a realização de testes de integração. Toda a comunicação com o ambiente sandbox deve ser feita através da url:\n\n```\nhttps://api.sandbox.cefispay.com.br/api/v1/\n```\n\n## Autenticação\nTodas as requisições que requerem autenticação, deverão informar no header `Authorization` o token de api enviado pela nossa equipe, observando sempre o ambiente desejado e no seguinte formato:\n```\nAuthorization: Bearer \n```\n\n## Headers\nRecomendamos que os cabeçalhos da requisições sejam corretamente adicionados para trabalhar com os tipos de dados enviados e recebidos da API:\n - Todas as requisições devem contem o header `Content-Type: application/json`, a menos que o endpoint específico defina diferente\n - Todas as requisições devem contem o header `Accept: application/json`, a menos que o endpoint específico defina diferente\n\n## Respostas\n- Os recursos vêm dentro de `data`: `GET /customers/{id}` responde `{ \"data\": { ... } }`.\n- As criações respondem **201**. `POST /payments` responde `{ \"customer\", \"payment\", \"invoice_url\" }` (o `invoice_url` só no boleto) e `POST /subscriptions` responde `{ \"customer\", \"subscription\" }`.\n- Valores sempre em centavos (inteiro): R$ 50,00 é `5000`.\n\n## Erros\nTodo erro tem o mesmo formato:\n```json\n{\n \"code\": \"VALIDATION_ERROR\",\n \"message\": \"Os dados informados são inválidos.\",\n \"errors\": { \"email\": [\"O campo email é obrigatório.\"] },\n \"timestamp\": \"2026-10-22T12:03:54+00:00\",\n \"request_id\": \"64d62d36-e797-45ed-a9d5-c203bde81032\",\n \"documentation_url\": \"https://docs.ninepay.com.br\",\n \"suggestion\": \"Corrija os campos e tente novamente.\"\n}\n```\n`errors` só vem na validação, com uma **lista** de mensagens por campo. `suggestion` vem quando há uma. Guarde o `request_id` para falar com o suporte.\n\n| `code` | HTTP | Quando |\n| --- | --- | --- |\n| `AUTHENTICATION_ERROR` | 401 | Token ausente ou inválido |\n| `FORBIDDEN_ERROR` | 403 | O recurso não é da sua empresa. Em várias rotas, um id que não existe também responde 403, para não revelar quais ids existem |\n| `COMPANYBLOCKED_ERROR` | 403 | A conta está suspensa |\n| `RESOURCE_NOT_FOUND_ERROR` | 404 | O recurso não existe |\n| `ROUTE_NOT_FOUND_ERROR` | 404 | A rota não existe |\n| `METHOD_NOT_ALLOWED_ERROR` | 405 | O método não vale para a rota (ex.: `PUT /customers` sem o id) |\n| `INVALID_STATE_ERROR` | 400 | O recurso não está num estado que permita a ação (ex.: cancelar um pagamento já pago) |\n| `VALIDATION_ERROR` | 422 | Dados inválidos; veja `errors` |\n| `REFUND_NOT_ALLOWED` | 422 | O pagamento não pode ser reembolsado |\n| `TOO_MANY_ATTEMPTS` | 429 | Muitas requisições; respeite o cabeçalho `Retry-After` |\n| `UNEXPECTED_ERROR` | 500 | Erro nosso; se repetir, fale com o suporte com o `request_id` |\n\n## Paginação\nAs listagens recebem `page` (a partir de 1) e `limit` (itens por página: **10** por padrão, de 1 a **100**). A resposta traz `data` (os itens), `links` e `meta` (`current_page`, `last_page`, `per_page`, `total`).\n\n## Datas\n- Datas de calendário (`due_date`, `next_payment`) vão como `AAAA-MM-DD` na requisição.\n- Nas respostas, os campos de data e hora aparecem em dois formatos: ISO 8601 em UTC (`2026-10-27T03:00:00.000000Z`, em `due_date` e `ref_date` do pagamento) e `AAAA-MM-DD HH:MM:SS` no horário de Brasília (`created_at` e `updated_at`). Leia o campo pelo formato dele.\n\n## Identificadores\nCada recurso tem um `id` numérico e um `uuid`. Use o `id` nas rotas autenticadas e o **`uuid`** em tudo que é público (o link de pagamento, o checkout e o PDF do boleto).\n\n# Hash de cartões\nO hash de um cartão é uma versão criptografada de todos os dados do cartão do cliente, essa é a maneira mais segura de enviar os dados do cartão\ndo seu cliente diretamente para a gente. Abaixo vamos detalhar como ele funciona e como obter um hash a partir dos dados inseridos pelo cliente.\nÉ importante ressaltar que esse fluxo deve ser executado no front-end, seja ele web ou mobile, e que os dados do cartão do cliente nunca devem\nser enviados para o backend, já o hash do cartão pode ser enviado para o backend sem problemas.\n\n## Gerando uma encryption key\nA encryption key consiste basicamente em uma chave pública RSA usada para encriptar os dados do cartão, essa chave só pode ser usada uma vez, então\nsempre que precisar encriptar um novo cartão você precisa gerar uma nova encryption key.\n\nPara gerar uma encryption key é necessário fazer uma requisição ``POST`` para a rota ``/encryption_keys`` da API enviando como parâmetro seu\n``merchant_id``. Ela não usa o token da API (nunca o coloque no front-end): o ``merchant_id`` identifica a sua conta, e um\n``merchant_id`` que não existe responde 401.\n\nA requisição deverá ter esse formato:\n```\ncurl -X POST https://payments.cefis.com.br/api/v1/encryption_keys -H 'Content-Type: application/json' -d '{\"merchant_id\":\"SEU_MERCHANT_ID\"}'\n```\n\nComo resposta você receberá um objeto JSON no seguinte formato:\n```\n{\n \"id\": 1111,\n \"public_key\": \"-----BEGIN PUBLIC KEY-----\\n ... \\n-----END PUBLIC KEY-----\\n\",\n \"ip_address\": \"000.000.000.000\",\n \"created_at\": \"2017-07-03\",\n}\n```\n\n## Encriptando os dados do cartão\nPara encriptar os dados do cartão primeiro você precisa formatá-los de forma correta, para isso crie uma string JSON\ncontendo todos os dados do cartão no seguinte formato:\n\n```\n{\"card_number\":\"1111111111111111\",\"card_holder_name\":\"Jose Silva\",\"card_expiration_date\":\"11/2021\",\"card_cvv\":\"111\"}\n```\n\nEm seguida faça a criptografia RSA dessa string utilizando a chave pública (public_key) gerada no passo anterior, com\npadding do tipo PKCS1.\n\nApós criptografar os dados converta a string resultante para base64 e você terá um resultado parecido com esse:\n\n```\nGprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nO último passo é concatenar o id da sua encryption key (recebido como resposta da requisição anterior) com a string\nem base64 que representa os dados do cartão, da seguinte forma:\n\n``encryption_key_id + \"_\" + base64_encrypted_card``\n\nO resultado será o seu card hash:\n\n```\n1111_GprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nPronto, agora os dados do cartão do cliente já estão em um formato seguro para serem transportados pela rede, podendo\nagora ser enviados para o seu back-end dar sequência ao fluxo. Vale lembrar que cada card hash pode ser usado apenas\numa vez e além disso tem uma validade máxima de 30 minutos após a geração da encryption key. Caso seja necessário utilizar\no cartão mais de uma vez faça uma requisição para a rota de cartões e salve esse cartão vinculado ao usuário que o detém,\nassim você receberá um ID único que poderá ser usado para realizar mais transações com o mesmo cartão.\n"
},
"paths": {
"/subscriptions/{id}/products": {
"post": {
"summary": "Anexar produtos à assinatura",
"tags": [
"Assinaturas"
],
"description": "Anexa produtos a uma assinatura já criada. Eles passam a ser cobrados junto do plano a partir da cobrança seguinte. Para que os produtos entrem já na primeira cobrança, envie-os no campo `products` na criação da assinatura.\n",
"requestBody": {
"$ref": "#/components/requestBodies/SubscriptionProductsBody"
},
"responses": {
"200": {
"description": "Produtos anexados com sucesso",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SubscriptionStoreResponse"
}
}
}
},
"401": {
"$ref": "#/components/responses/401"
},
"422": {
"$ref": "#/components/responses/422"
},
"500": {
"$ref": "#/components/responses/500"
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
]
}
}
},
"components": {
"securitySchemes": {
"Bearer": {
"type": "apiKey",
"in": "header",
"name": "Authorization",
"description": "Todas as requisições que requerem autenticação devem incluir no cabeçalho `Authorization` o token de API enviado pela nossa equipe. O token deve ser fornecido no seguinte formato:\n```\nAuthorization: Bearer \n```"
}
},
"responses": {
"401": {
"description": "Não autenticado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "AUTHENTICATION_ERROR",
"message": "Não autenticado.",
"timestamp": "2026-10-22T12:03:44+00:00",
"request_id": "f2a7e962-6083-4525-816e-f14d4a602e0a",
"documentation_url": "https://docs.ninepay.com.br"
}
}
}
},
"422": {
"description": "Erro na validação dos dados",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "VALIDATION_ERROR",
"message": "Os dados informados são inválidos.",
"errors": {
"email": [
"O campo email é obrigatório."
]
},
"timestamp": "2026-10-22T12:03:54+00:00",
"request_id": "64d62d36-e797-45ed-a9d5-c203bde81032",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Corrija os campos e tente novamente."
}
}
}
},
"500": {
"description": "Erro inesperado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "UNEXPECTED_ERROR",
"message": "Houve um erro inesperado.",
"timestamp": "2026-10-22T12:04:46+00:00",
"request_id": "868443d3-38fd-4c92-8ea8-7cccbbce4308",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Verifique todos os parâmetros da requisição. Se o erro persistir, entre em contato com nossa equipe em ti@ninepay.com.br."
}
}
}
}
},
"schemas": {
"ApiError": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "O código do erro. Ex.: `VALIDATION_ERROR`, `FORBIDDEN_ERROR`, `UNEXPECTED_ERROR`."
},
"message": {
"type": "string",
"description": "A mensagem do erro."
},
"errors": {
"type": "object",
"description": "Os erros de cada campo, quando o `code` é `VALIDATION_ERROR`.",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "A data e hora do erro, em UTC."
},
"request_id": {
"type": "string",
"description": "Um identificador único gerado para esta resposta de erro."
},
"documentation_url": {
"type": "string",
"description": "O endereço desta documentação."
},
"suggestion": {
"type": "string",
"description": "Uma sugestão de como resolver o erro."
}
}
},
"SubscriptionStoreResponse": {
"type": "object",
"properties": {
"subscription": {
"$ref": "#/components/schemas/Subscription"
},
"customer": {
"$ref": "#/components/schemas/Customer"
}
}
},
"Customer": {
"type": "object",
"required": [
"id",
"name",
"email",
"cpf",
"cnpj"
],
"properties": {
"id": {
"description": "O id do cliente na NinePay. Obrigatório se os demais dados do usuário não forem informados",
"type": "integer",
"example": 42,
"readOnly": true
},
"name": {
"description": "O nome do cliente. Obrigatório se o `id` não for informado",
"type": "string",
"example": "Jhon Doe"
},
"email": {
"description": "O email do cliente. Obrigatório se o `id` não for informado",
"type": "string",
"example": "jhon@doe.com"
},
"cpf": {
"description": "O cpf do cliente. Obrigatório se o `id` ou o `cnpj` não forem informados",
"type": "string",
"example": "833.828.600-15"
},
"cnpj": {
"description": "O cnpj do cliente. Obrigatório se o `id` ou o `cpf` não forem informados",
"type": "string",
"example": "95.135.209/0001-79"
},
"phone": {
"description": "O telefone celular do cliente, com DDD. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": "(11) 11111-1111"
},
"cep": {
"description": "O CEP do cliente. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": "01423-910"
},
"address": {
"description": "O endereço do cliente",
"type": "string",
"example": "Rua José Maria Lisboa"
},
"number": {
"description": "O número do endereço do cliente. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": 42
},
"district": {
"description": "O bairro do cliente",
"type": "string",
"example": "Jardim Paulista"
},
"city": {
"description": "A cidade do cliente",
"type": "string",
"example": "São Paulo"
},
"state": {
"description": "O estado do cliente",
"type": "string",
"example": "SP"
},
"country": {
"description": "O código do país do cliente, no formato Alpha 2 de acordo com a [ISO 3166](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes).",
"type": "string",
"example": "BR"
}
}
},
"Subscription": {
"type": "object",
"properties": {
"id": {
"description": "O id da assinatura.",
"type": "integer",
"example": 42,
"readOnly": true
},
"uuid": {
"description": "O id publico da assinatura. Esse id pode ser usado para levar o cliente a página de checkout para pagamento.",
"type": "string",
"format": "uuid",
"example": "8b2cad02-06f0-42be-84ac-101b23a1bb0d"
},
"amount": {
"description": "O valor da assinatura em centavos.",
"type": "number",
"example": 2500
},
"plan_id": {
"description": "O id do plano.",
"type": "number",
"example": 2500
},
"status": {
"description": "O status da assinatura.",
"$ref": "#/components/schemas/SubscriptionStatus",
"example": "credit"
},
"created_at": {
"description": "Data de criação.",
"type": "string",
"format": "date-time",
"example": "2017-07-21 05:20:00"
}
}
},
"SubscriptionStatus": {
"type": "string",
"enum": [
"new",
"trial",
"active",
"overdue",
"canceled",
"expired",
"paused"
]
},
"SubscriptionProductsBody": {
"type": "object",
"required": [
"products"
],
"properties": {
"products": {
"type": "array",
"description": "Os produtos a anexar à assinatura.",
"items": {
"type": "object",
"required": [
"identifier",
"value"
],
"properties": {
"identifier": {
"type": "string",
"maxLength": 50,
"description": "O nome do produto, como aparece na cobrança.",
"example": "Membro adicional"
},
"value": {
"type": "integer",
"description": "O valor do produto, em centavos.",
"example": 1290
},
"name": {
"type": "string",
"maxLength": 191,
"description": "Opcional. O que o cliente lê na cobrança. O `identifier` é a chave pela qual o produto é removido, então costuma ser um valor técnico; o `name` é o rótulo apresentável. Sem `name`, o `identifier` continua sendo exibido.\n",
"example": "Membro adicional"
}
}
}
}
}
}
},
"requestBodies": {
"SubscriptionProductsBody": {
"required": true,
"description": "Descreve os dados a serem incluídos no corpo da requisição.\n",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SubscriptionProductsBody"
}
}
}
}
}
},
"tags": [
{
"name": "Assinaturas",
"description": "Assinaturas"
}
],
"x-tagGroups": [
{
"name": "API Calls",
"tags": [
"Pagamentos",
"Clientes",
"Planos",
"Assinaturas",
"Consultas"
]
}
],
"servers": [
{
"url": "https://api.sandbox.cefispay.com.br/api/v1",
"description": "Servidor de Testes (sandbox)"
}
],
"security": [
{
"Bearer": []
}
]
}
```
---
# Remover um produto da assinatura
Source: https://docs.ninepay.com.br/reference/remover-um-produto-da-assinatura
Remove um produto da assinatura, que deixa de ser cobrado a partir da cobrança seguinte. Quando nenhum produto da assinatura tem o `identifier` informado, o produto mais antigo é removido.
# OpenAPI definition
```json
{
"openapi": "3.0.3",
"info": {
"title": "NinePay API",
"version": "1.0",
"x-logo": {
"url": ""
},
"termsOfService": "https://bit.ly/cefispay-contrato",
"contact": {
"name": "NinePay Engineering Team",
"email": "ti@ninepay.com.br"
},
"description": "# Introdução\nBem vindo a referência da **API NinePay**.\nÉ através desta API que você integra o seu sistema ao nosso.\nNossa API é RESTful, e todas suas respostas são em JSON, no endpoint base:\n```\nhttps://payments.cefis.com.br/api/v1/\n```\n\n## Ambientes\nAlém do ambiente de **produção** temos disponível o ambiente **sandbox**\npara a realização de testes de integração. Toda a comunicação com o ambiente sandbox deve ser feita através da url:\n\n```\nhttps://api.sandbox.cefispay.com.br/api/v1/\n```\n\n## Autenticação\nTodas as requisições que requerem autenticação, deverão informar no header `Authorization` o token de api enviado pela nossa equipe, observando sempre o ambiente desejado e no seguinte formato:\n```\nAuthorization: Bearer \n```\n\n## Headers\nRecomendamos que os cabeçalhos da requisições sejam corretamente adicionados para trabalhar com os tipos de dados enviados e recebidos da API:\n - Todas as requisições devem contem o header `Content-Type: application/json`, a menos que o endpoint específico defina diferente\n - Todas as requisições devem contem o header `Accept: application/json`, a menos que o endpoint específico defina diferente\n\n## Respostas\n- Os recursos vêm dentro de `data`: `GET /customers/{id}` responde `{ \"data\": { ... } }`.\n- As criações respondem **201**. `POST /payments` responde `{ \"customer\", \"payment\", \"invoice_url\" }` (o `invoice_url` só no boleto) e `POST /subscriptions` responde `{ \"customer\", \"subscription\" }`.\n- Valores sempre em centavos (inteiro): R$ 50,00 é `5000`.\n\n## Erros\nTodo erro tem o mesmo formato:\n```json\n{\n \"code\": \"VALIDATION_ERROR\",\n \"message\": \"Os dados informados são inválidos.\",\n \"errors\": { \"email\": [\"O campo email é obrigatório.\"] },\n \"timestamp\": \"2026-10-22T12:03:54+00:00\",\n \"request_id\": \"64d62d36-e797-45ed-a9d5-c203bde81032\",\n \"documentation_url\": \"https://docs.ninepay.com.br\",\n \"suggestion\": \"Corrija os campos e tente novamente.\"\n}\n```\n`errors` só vem na validação, com uma **lista** de mensagens por campo. `suggestion` vem quando há uma. Guarde o `request_id` para falar com o suporte.\n\n| `code` | HTTP | Quando |\n| --- | --- | --- |\n| `AUTHENTICATION_ERROR` | 401 | Token ausente ou inválido |\n| `FORBIDDEN_ERROR` | 403 | O recurso não é da sua empresa. Em várias rotas, um id que não existe também responde 403, para não revelar quais ids existem |\n| `COMPANYBLOCKED_ERROR` | 403 | A conta está suspensa |\n| `RESOURCE_NOT_FOUND_ERROR` | 404 | O recurso não existe |\n| `ROUTE_NOT_FOUND_ERROR` | 404 | A rota não existe |\n| `METHOD_NOT_ALLOWED_ERROR` | 405 | O método não vale para a rota (ex.: `PUT /customers` sem o id) |\n| `INVALID_STATE_ERROR` | 400 | O recurso não está num estado que permita a ação (ex.: cancelar um pagamento já pago) |\n| `VALIDATION_ERROR` | 422 | Dados inválidos; veja `errors` |\n| `REFUND_NOT_ALLOWED` | 422 | O pagamento não pode ser reembolsado |\n| `TOO_MANY_ATTEMPTS` | 429 | Muitas requisições; respeite o cabeçalho `Retry-After` |\n| `UNEXPECTED_ERROR` | 500 | Erro nosso; se repetir, fale com o suporte com o `request_id` |\n\n## Paginação\nAs listagens recebem `page` (a partir de 1) e `limit` (itens por página: **10** por padrão, de 1 a **100**). A resposta traz `data` (os itens), `links` e `meta` (`current_page`, `last_page`, `per_page`, `total`).\n\n## Datas\n- Datas de calendário (`due_date`, `next_payment`) vão como `AAAA-MM-DD` na requisição.\n- Nas respostas, os campos de data e hora aparecem em dois formatos: ISO 8601 em UTC (`2026-10-27T03:00:00.000000Z`, em `due_date` e `ref_date` do pagamento) e `AAAA-MM-DD HH:MM:SS` no horário de Brasília (`created_at` e `updated_at`). Leia o campo pelo formato dele.\n\n## Identificadores\nCada recurso tem um `id` numérico e um `uuid`. Use o `id` nas rotas autenticadas e o **`uuid`** em tudo que é público (o link de pagamento, o checkout e o PDF do boleto).\n\n# Hash de cartões\nO hash de um cartão é uma versão criptografada de todos os dados do cartão do cliente, essa é a maneira mais segura de enviar os dados do cartão\ndo seu cliente diretamente para a gente. Abaixo vamos detalhar como ele funciona e como obter um hash a partir dos dados inseridos pelo cliente.\nÉ importante ressaltar que esse fluxo deve ser executado no front-end, seja ele web ou mobile, e que os dados do cartão do cliente nunca devem\nser enviados para o backend, já o hash do cartão pode ser enviado para o backend sem problemas.\n\n## Gerando uma encryption key\nA encryption key consiste basicamente em uma chave pública RSA usada para encriptar os dados do cartão, essa chave só pode ser usada uma vez, então\nsempre que precisar encriptar um novo cartão você precisa gerar uma nova encryption key.\n\nPara gerar uma encryption key é necessário fazer uma requisição ``POST`` para a rota ``/encryption_keys`` da API enviando como parâmetro seu\n``merchant_id``. Ela não usa o token da API (nunca o coloque no front-end): o ``merchant_id`` identifica a sua conta, e um\n``merchant_id`` que não existe responde 401.\n\nA requisição deverá ter esse formato:\n```\ncurl -X POST https://payments.cefis.com.br/api/v1/encryption_keys -H 'Content-Type: application/json' -d '{\"merchant_id\":\"SEU_MERCHANT_ID\"}'\n```\n\nComo resposta você receberá um objeto JSON no seguinte formato:\n```\n{\n \"id\": 1111,\n \"public_key\": \"-----BEGIN PUBLIC KEY-----\\n ... \\n-----END PUBLIC KEY-----\\n\",\n \"ip_address\": \"000.000.000.000\",\n \"created_at\": \"2017-07-03\",\n}\n```\n\n## Encriptando os dados do cartão\nPara encriptar os dados do cartão primeiro você precisa formatá-los de forma correta, para isso crie uma string JSON\ncontendo todos os dados do cartão no seguinte formato:\n\n```\n{\"card_number\":\"1111111111111111\",\"card_holder_name\":\"Jose Silva\",\"card_expiration_date\":\"11/2021\",\"card_cvv\":\"111\"}\n```\n\nEm seguida faça a criptografia RSA dessa string utilizando a chave pública (public_key) gerada no passo anterior, com\npadding do tipo PKCS1.\n\nApós criptografar os dados converta a string resultante para base64 e você terá um resultado parecido com esse:\n\n```\nGprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nO último passo é concatenar o id da sua encryption key (recebido como resposta da requisição anterior) com a string\nem base64 que representa os dados do cartão, da seguinte forma:\n\n``encryption_key_id + \"_\" + base64_encrypted_card``\n\nO resultado será o seu card hash:\n\n```\n1111_GprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nPronto, agora os dados do cartão do cliente já estão em um formato seguro para serem transportados pela rede, podendo\nagora ser enviados para o seu back-end dar sequência ao fluxo. Vale lembrar que cada card hash pode ser usado apenas\numa vez e além disso tem uma validade máxima de 30 minutos após a geração da encryption key. Caso seja necessário utilizar\no cartão mais de uma vez faça uma requisição para a rota de cartões e salve esse cartão vinculado ao usuário que o detém,\nassim você receberá um ID único que poderá ser usado para realizar mais transações com o mesmo cartão.\n"
},
"paths": {
"/subscriptions/{id}/products/{identifier}": {
"delete": {
"summary": "Remover um produto da assinatura",
"tags": [
"Assinaturas"
],
"description": "Remove um produto da assinatura, que deixa de ser cobrado a partir da cobrança seguinte. Quando nenhum produto da assinatura tem o `identifier` informado, o produto mais antigo é removido.\n",
"responses": {
"200": {
"description": "Produto removido com sucesso",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SubscriptionStoreResponse"
}
}
}
},
"401": {
"$ref": "#/components/responses/401"
},
"422": {
"$ref": "#/components/responses/422"
},
"500": {
"$ref": "#/components/responses/500"
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "identifier",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
]
}
}
},
"components": {
"securitySchemes": {
"Bearer": {
"type": "apiKey",
"in": "header",
"name": "Authorization",
"description": "Todas as requisições que requerem autenticação devem incluir no cabeçalho `Authorization` o token de API enviado pela nossa equipe. O token deve ser fornecido no seguinte formato:\n```\nAuthorization: Bearer \n```"
}
},
"responses": {
"401": {
"description": "Não autenticado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "AUTHENTICATION_ERROR",
"message": "Não autenticado.",
"timestamp": "2026-10-22T12:03:44+00:00",
"request_id": "f2a7e962-6083-4525-816e-f14d4a602e0a",
"documentation_url": "https://docs.ninepay.com.br"
}
}
}
},
"422": {
"description": "Erro na validação dos dados",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "VALIDATION_ERROR",
"message": "Os dados informados são inválidos.",
"errors": {
"email": [
"O campo email é obrigatório."
]
},
"timestamp": "2026-10-22T12:03:54+00:00",
"request_id": "64d62d36-e797-45ed-a9d5-c203bde81032",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Corrija os campos e tente novamente."
}
}
}
},
"500": {
"description": "Erro inesperado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "UNEXPECTED_ERROR",
"message": "Houve um erro inesperado.",
"timestamp": "2026-10-22T12:04:46+00:00",
"request_id": "868443d3-38fd-4c92-8ea8-7cccbbce4308",
"documentation_url": "https://docs.ninepay.com.br",
"suggestion": "Verifique todos os parâmetros da requisição. Se o erro persistir, entre em contato com nossa equipe em ti@ninepay.com.br."
}
}
}
}
},
"schemas": {
"ApiError": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "O código do erro. Ex.: `VALIDATION_ERROR`, `FORBIDDEN_ERROR`, `UNEXPECTED_ERROR`."
},
"message": {
"type": "string",
"description": "A mensagem do erro."
},
"errors": {
"type": "object",
"description": "Os erros de cada campo, quando o `code` é `VALIDATION_ERROR`.",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "A data e hora do erro, em UTC."
},
"request_id": {
"type": "string",
"description": "Um identificador único gerado para esta resposta de erro."
},
"documentation_url": {
"type": "string",
"description": "O endereço desta documentação."
},
"suggestion": {
"type": "string",
"description": "Uma sugestão de como resolver o erro."
}
}
},
"SubscriptionStoreResponse": {
"type": "object",
"properties": {
"subscription": {
"$ref": "#/components/schemas/Subscription"
},
"customer": {
"$ref": "#/components/schemas/Customer"
}
}
},
"Customer": {
"type": "object",
"required": [
"id",
"name",
"email",
"cpf",
"cnpj"
],
"properties": {
"id": {
"description": "O id do cliente na NinePay. Obrigatório se os demais dados do usuário não forem informados",
"type": "integer",
"example": 42,
"readOnly": true
},
"name": {
"description": "O nome do cliente. Obrigatório se o `id` não for informado",
"type": "string",
"example": "Jhon Doe"
},
"email": {
"description": "O email do cliente. Obrigatório se o `id` não for informado",
"type": "string",
"example": "jhon@doe.com"
},
"cpf": {
"description": "O cpf do cliente. Obrigatório se o `id` ou o `cnpj` não forem informados",
"type": "string",
"example": "833.828.600-15"
},
"cnpj": {
"description": "O cnpj do cliente. Obrigatório se o `id` ou o `cpf` não forem informados",
"type": "string",
"example": "95.135.209/0001-79"
},
"phone": {
"description": "O telefone celular do cliente, com DDD. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": "(11) 11111-1111"
},
"cep": {
"description": "O CEP do cliente. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": "01423-910"
},
"address": {
"description": "O endereço do cliente",
"type": "string",
"example": "Rua José Maria Lisboa"
},
"number": {
"description": "O número do endereço do cliente. Obrigatório para cobranças no cartão de crédito.",
"type": "string",
"example": 42
},
"district": {
"description": "O bairro do cliente",
"type": "string",
"example": "Jardim Paulista"
},
"city": {
"description": "A cidade do cliente",
"type": "string",
"example": "São Paulo"
},
"state": {
"description": "O estado do cliente",
"type": "string",
"example": "SP"
},
"country": {
"description": "O código do país do cliente, no formato Alpha 2 de acordo com a [ISO 3166](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes).",
"type": "string",
"example": "BR"
}
}
},
"Subscription": {
"type": "object",
"properties": {
"id": {
"description": "O id da assinatura.",
"type": "integer",
"example": 42,
"readOnly": true
},
"uuid": {
"description": "O id publico da assinatura. Esse id pode ser usado para levar o cliente a página de checkout para pagamento.",
"type": "string",
"format": "uuid",
"example": "8b2cad02-06f0-42be-84ac-101b23a1bb0d"
},
"amount": {
"description": "O valor da assinatura em centavos.",
"type": "number",
"example": 2500
},
"plan_id": {
"description": "O id do plano.",
"type": "number",
"example": 2500
},
"status": {
"description": "O status da assinatura.",
"$ref": "#/components/schemas/SubscriptionStatus",
"example": "credit"
},
"created_at": {
"description": "Data de criação.",
"type": "string",
"format": "date-time",
"example": "2017-07-21 05:20:00"
}
}
},
"SubscriptionStatus": {
"type": "string",
"enum": [
"new",
"trial",
"active",
"overdue",
"canceled",
"expired",
"paused"
]
}
}
},
"tags": [
{
"name": "Assinaturas",
"description": "Assinaturas"
}
],
"x-tagGroups": [
{
"name": "API Calls",
"tags": [
"Pagamentos",
"Clientes",
"Planos",
"Assinaturas",
"Consultas"
]
}
],
"servers": [
{
"url": "https://api.sandbox.cefispay.com.br/api/v1",
"description": "Servidor de Testes (sandbox)"
}
],
"security": [
{
"Bearer": []
}
]
}
```
---
# Consultar CNPJ
Source: https://docs.ninepay.com.br/reference/consultar-cnpj
Retorna os dados cadastrais de uma empresa pelo CNPJ, como razão social, nome fantasia e endereço, para preencher formulários de cadastro e cobrança. O CNPJ pode ser enviado com ou sem pontuação (sem a barra, que quebraria o caminho). **Limite:** 30 consultas por minuto por token.
# OpenAPI definition
```json
{
"openapi": "3.0.3",
"info": {
"title": "NinePay API",
"version": "1.0",
"x-logo": {
"url": ""
},
"termsOfService": "https://bit.ly/cefispay-contrato",
"contact": {
"name": "NinePay Engineering Team",
"email": "ti@ninepay.com.br"
},
"description": "# Introdução\nBem vindo a referência da **API NinePay**.\nÉ através desta API que você integra o seu sistema ao nosso.\nNossa API é RESTful, e todas suas respostas são em JSON, no endpoint base:\n```\nhttps://payments.cefis.com.br/api/v1/\n```\n\n## Ambientes\nAlém do ambiente de **produção** temos disponível o ambiente **sandbox**\npara a realização de testes de integração. Toda a comunicação com o ambiente sandbox deve ser feita através da url:\n\n```\nhttps://api.sandbox.cefispay.com.br/api/v1/\n```\n\n## Autenticação\nTodas as requisições que requerem autenticação, deverão informar no header `Authorization` o token de api enviado pela nossa equipe, observando sempre o ambiente desejado e no seguinte formato:\n```\nAuthorization: Bearer \n```\n\n## Headers\nRecomendamos que os cabeçalhos da requisições sejam corretamente adicionados para trabalhar com os tipos de dados enviados e recebidos da API:\n - Todas as requisições devem contem o header `Content-Type: application/json`, a menos que o endpoint específico defina diferente\n - Todas as requisições devem contem o header `Accept: application/json`, a menos que o endpoint específico defina diferente\n\n## Respostas\n- Os recursos vêm dentro de `data`: `GET /customers/{id}` responde `{ \"data\": { ... } }`.\n- As criações respondem **201**. `POST /payments` responde `{ \"customer\", \"payment\", \"invoice_url\" }` (o `invoice_url` só no boleto) e `POST /subscriptions` responde `{ \"customer\", \"subscription\" }`.\n- Valores sempre em centavos (inteiro): R$ 50,00 é `5000`.\n\n## Erros\nTodo erro tem o mesmo formato:\n```json\n{\n \"code\": \"VALIDATION_ERROR\",\n \"message\": \"Os dados informados são inválidos.\",\n \"errors\": { \"email\": [\"O campo email é obrigatório.\"] },\n \"timestamp\": \"2026-10-22T12:03:54+00:00\",\n \"request_id\": \"64d62d36-e797-45ed-a9d5-c203bde81032\",\n \"documentation_url\": \"https://docs.ninepay.com.br\",\n \"suggestion\": \"Corrija os campos e tente novamente.\"\n}\n```\n`errors` só vem na validação, com uma **lista** de mensagens por campo. `suggestion` vem quando há uma. Guarde o `request_id` para falar com o suporte.\n\n| `code` | HTTP | Quando |\n| --- | --- | --- |\n| `AUTHENTICATION_ERROR` | 401 | Token ausente ou inválido |\n| `FORBIDDEN_ERROR` | 403 | O recurso não é da sua empresa. Em várias rotas, um id que não existe também responde 403, para não revelar quais ids existem |\n| `COMPANYBLOCKED_ERROR` | 403 | A conta está suspensa |\n| `RESOURCE_NOT_FOUND_ERROR` | 404 | O recurso não existe |\n| `ROUTE_NOT_FOUND_ERROR` | 404 | A rota não existe |\n| `METHOD_NOT_ALLOWED_ERROR` | 405 | O método não vale para a rota (ex.: `PUT /customers` sem o id) |\n| `INVALID_STATE_ERROR` | 400 | O recurso não está num estado que permita a ação (ex.: cancelar um pagamento já pago) |\n| `VALIDATION_ERROR` | 422 | Dados inválidos; veja `errors` |\n| `REFUND_NOT_ALLOWED` | 422 | O pagamento não pode ser reembolsado |\n| `TOO_MANY_ATTEMPTS` | 429 | Muitas requisições; respeite o cabeçalho `Retry-After` |\n| `UNEXPECTED_ERROR` | 500 | Erro nosso; se repetir, fale com o suporte com o `request_id` |\n\n## Paginação\nAs listagens recebem `page` (a partir de 1) e `limit` (itens por página: **10** por padrão, de 1 a **100**). A resposta traz `data` (os itens), `links` e `meta` (`current_page`, `last_page`, `per_page`, `total`).\n\n## Datas\n- Datas de calendário (`due_date`, `next_payment`) vão como `AAAA-MM-DD` na requisição.\n- Nas respostas, os campos de data e hora aparecem em dois formatos: ISO 8601 em UTC (`2026-10-27T03:00:00.000000Z`, em `due_date` e `ref_date` do pagamento) e `AAAA-MM-DD HH:MM:SS` no horário de Brasília (`created_at` e `updated_at`). Leia o campo pelo formato dele.\n\n## Identificadores\nCada recurso tem um `id` numérico e um `uuid`. Use o `id` nas rotas autenticadas e o **`uuid`** em tudo que é público (o link de pagamento, o checkout e o PDF do boleto).\n\n# Hash de cartões\nO hash de um cartão é uma versão criptografada de todos os dados do cartão do cliente, essa é a maneira mais segura de enviar os dados do cartão\ndo seu cliente diretamente para a gente. Abaixo vamos detalhar como ele funciona e como obter um hash a partir dos dados inseridos pelo cliente.\nÉ importante ressaltar que esse fluxo deve ser executado no front-end, seja ele web ou mobile, e que os dados do cartão do cliente nunca devem\nser enviados para o backend, já o hash do cartão pode ser enviado para o backend sem problemas.\n\n## Gerando uma encryption key\nA encryption key consiste basicamente em uma chave pública RSA usada para encriptar os dados do cartão, essa chave só pode ser usada uma vez, então\nsempre que precisar encriptar um novo cartão você precisa gerar uma nova encryption key.\n\nPara gerar uma encryption key é necessário fazer uma requisição ``POST`` para a rota ``/encryption_keys`` da API enviando como parâmetro seu\n``merchant_id``. Ela não usa o token da API (nunca o coloque no front-end): o ``merchant_id`` identifica a sua conta, e um\n``merchant_id`` que não existe responde 401.\n\nA requisição deverá ter esse formato:\n```\ncurl -X POST https://payments.cefis.com.br/api/v1/encryption_keys -H 'Content-Type: application/json' -d '{\"merchant_id\":\"SEU_MERCHANT_ID\"}'\n```\n\nComo resposta você receberá um objeto JSON no seguinte formato:\n```\n{\n \"id\": 1111,\n \"public_key\": \"-----BEGIN PUBLIC KEY-----\\n ... \\n-----END PUBLIC KEY-----\\n\",\n \"ip_address\": \"000.000.000.000\",\n \"created_at\": \"2017-07-03\",\n}\n```\n\n## Encriptando os dados do cartão\nPara encriptar os dados do cartão primeiro você precisa formatá-los de forma correta, para isso crie uma string JSON\ncontendo todos os dados do cartão no seguinte formato:\n\n```\n{\"card_number\":\"1111111111111111\",\"card_holder_name\":\"Jose Silva\",\"card_expiration_date\":\"11/2021\",\"card_cvv\":\"111\"}\n```\n\nEm seguida faça a criptografia RSA dessa string utilizando a chave pública (public_key) gerada no passo anterior, com\npadding do tipo PKCS1.\n\nApós criptografar os dados converta a string resultante para base64 e você terá um resultado parecido com esse:\n\n```\nGprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nO último passo é concatenar o id da sua encryption key (recebido como resposta da requisição anterior) com a string\nem base64 que representa os dados do cartão, da seguinte forma:\n\n``encryption_key_id + \"_\" + base64_encrypted_card``\n\nO resultado será o seu card hash:\n\n```\n1111_GprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==\n```\n\nPronto, agora os dados do cartão do cliente já estão em um formato seguro para serem transportados pela rede, podendo\nagora ser enviados para o seu back-end dar sequência ao fluxo. Vale lembrar que cada card hash pode ser usado apenas\numa vez e além disso tem uma validade máxima de 30 minutos após a geração da encryption key. Caso seja necessário utilizar\no cartão mais de uma vez faça uma requisição para a rota de cartões e salve esse cartão vinculado ao usuário que o detém,\nassim você receberá um ID único que poderá ser usado para realizar mais transações com o mesmo cartão.\n"
},
"paths": {
"/cnpj/{cnpj}": {
"get": {
"summary": "Consultar CNPJ",
"tags": [
"Consultas"
],
"description": "Retorna os dados cadastrais de uma empresa pelo CNPJ, como razão social, nome fantasia e endereço, para preencher formulários de cadastro e cobrança. O CNPJ pode ser enviado com ou sem pontuação (sem a barra, que quebraria o caminho). **Limite:** 30 consultas por minuto por token.\n",
"parameters": [
{
"name": "cnpj",
"in": "path",
"required": true,
"description": "CNPJ com 14 dígitos.",
"schema": {
"type": "string",
"example": "00000000000191"
}
}
],
"responses": {
"200": {
"description": "Dados da empresa",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"taxId": {
"type": "string",
"example": "00000000000191"
},
"alias": {
"type": "string",
"nullable": true,
"description": "Nome fantasia",
"example": "Banco do Brasil"
},
"company": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Razão social",
"example": "BANCO DO BRASIL SA"
}
}
},
"address": {
"type": "object",
"properties": {
"street": {
"type": "string"
},
"number": {
"type": "string"
},
"details": {
"type": "string",
"nullable": true
},
"district": {
"type": "string"
},
"city": {
"type": "string"
},
"state": {
"type": "string"
},
"zip": {
"type": "string"
}
}
}
}
}
}
}
}
}
},
"401": {
"$ref": "#/components/responses/401"
},
"422": {
"description": "CNPJ sem 14 dígitos",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string",
"example": "CNPJ inválido."
}
}
}
}
}
},
"429": {
"description": "Limite de consultas por minuto atingido"
},
"502": {
"description": "Não foi possível consultar o CNPJ no momento",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string",
"example": "Não foi possível consultar o CNPJ."
}
}
}
}
}
}
}
}
}
},
"components": {
"securitySchemes": {
"Bearer": {
"type": "apiKey",
"in": "header",
"name": "Authorization",
"description": "Todas as requisições que requerem autenticação devem incluir no cabeçalho `Authorization` o token de API enviado pela nossa equipe. O token deve ser fornecido no seguinte formato:\n```\nAuthorization: Bearer \n```"
}
},
"responses": {
"401": {
"description": "Não autenticado",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiError"
},
"example": {
"code": "AUTHENTICATION_ERROR",
"message": "Não autenticado.",
"timestamp": "2026-10-22T12:03:44+00:00",
"request_id": "f2a7e962-6083-4525-816e-f14d4a602e0a",
"documentation_url": "https://docs.ninepay.com.br"
}
}
}
}
},
"schemas": {
"ApiError": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "O código do erro. Ex.: `VALIDATION_ERROR`, `FORBIDDEN_ERROR`, `UNEXPECTED_ERROR`."
},
"message": {
"type": "string",
"description": "A mensagem do erro."
},
"errors": {
"type": "object",
"description": "Os erros de cada campo, quando o `code` é `VALIDATION_ERROR`.",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "A data e hora do erro, em UTC."
},
"request_id": {
"type": "string",
"description": "Um identificador único gerado para esta resposta de erro."
},
"documentation_url": {
"type": "string",
"description": "O endereço desta documentação."
},
"suggestion": {
"type": "string",
"description": "Uma sugestão de como resolver o erro."
}
}
}
}
},
"tags": [
{
"name": "Consultas",
"description": "Consultas"
}
],
"x-tagGroups": [
{
"name": "API Calls",
"tags": [
"Pagamentos",
"Clientes",
"Planos",
"Assinaturas",
"Consultas"
]
}
],
"servers": [
{
"url": "https://api.sandbox.cefispay.com.br/api/v1",
"description": "Servidor de Testes (sandbox)"
}
],
"security": [
{
"Bearer": []
}
]
}
```
---
# Checkout embutido (ninepay.js)
Source: https://docs.ninepay.com.br/recipes/checkout-embutido
Coloque o pagamento de uma fatura dentro da sua página, com o seu botão de pagar e o iframe da NinePay para cartão, PIX e boleto.
## Crie a fatura no servidor
> Linhas destacadas: 8
No seu servidor, com o token da API, crie a cobrança em aberto com `open: true` e os métodos que o iframe pode oferecer. Nada é cobrado na criação. Mande para a página só o `payment.uuid` da resposta; o token nunca vai para o navegador.
```bash
curl -X POST https://api.sandbox.cefispay.com.br/api/v1/payments \
-H "Authorization: Bearer $NINEPAY_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"customer": { "id": 123 },
"method": "credit",
"open": true,
"allowed_methods": ["credit", "pix", "billet"],
"value": 5000,
"due_date": "2026-11-10"
}'
```
Antes, cadastre no dashboard (Integrações → Checkout embutido) o endereço do site que vai abrir o checkout; sem ele, o navegador recusa o iframe.
## Carregue o ninepay.js
> Linhas destacadas: 4-6
Carregue o script sempre de `https://checkout.ninepay.com.br/js/v1/ninepay.js`, nunca de uma cópia. Para o sandbox, passe a origem do ambiente em `Ninepay({ origin })`. O CSP da página precisa liberar `https://checkout.ninepay.com.br` em `script-src` e `frame-src`.
## Monte o elemento
> Linhas destacadas: 7-11
`ninepay.elements` recebe o `uuid` da fatura (e, se quiser, `appearance` para combinar com a sua página). `elements.create('payment')` cria o iframe com os métodos da fatura, e `mount` o coloca no lugar.
## Habilite o botão
> Linhas destacadas: 13-16
O botão de pagar é da sua página. O evento `change` avisa quando os campos do método escolhido estão completos.
## Valide e pague
> Linhas destacadas: 18-31
`elements.submit()` valida e mostra os erros no iframe, sem enviar. Depois, `ninepay.confirmPayment({ elements })` paga e sempre resolve, com `{ payment }` ou `{ error }`. No sandbox, teste com os [cartões de teste](/docs/test-cards).
## Acompanhe o pagamento
> Linhas destacadas: 33-35
O evento `paid` chega quando o pagamento é feito nesta tela, inclusive o PIX ou o boleto pagos depois. Use para atualizar a tela; libere o acesso só pelo webhook, confirmando com `GET /payments/{id}`.
## Código
```html HTML
```
---
# Cobrança no cartão de crédito
Source: https://docs.ninepay.com.br/recipes/cobranca-no-cartao-de-credito
Gere um card hash com um cartão de teste do sandbox, cobre no cartão em parcelas e confira o status.
## Gere uma encryption key
> Linhas destacadas: 5-11
`POST /encryption_keys` recebe o seu `merchant_id` e devolve uma chave pública RSA (`public_key`) e o `id` dela. Cada chave serve para um cartão só.
> 🚧 Em produção, isto roda no front-end
> Os passos 1 e 2 estão em Node só para testar no sandbox com um cartão de teste. Com cartões de verdade, gere o hash no navegador ou no app: os dados do cartão nunca devem passar pelo seu back-end. Veja [Hash de cartões](/docs/introducao-api#hash-de-cartoes).
## Encripte o cartão
> Linhas destacadas: 13-24
Monte o JSON do cartão, encripte com a `public_key` usando padding PKCS1, converta para base64 e junte com o `id` da chave: `id_base64`. O hash vale uma vez e por até 30 minutos.
No sandbox, o último dígito do cartão decide o resultado: final **0** aprova, finais **1 a 9** recusam. Use validade futura e qualquer CVV de 3 dígitos. Veja os [cartões de teste](/docs/test-cards).
## Cobre no cartão
> Linhas destacadas: 26-42
Envie `method: "credit"`, o `card_hash` e, se quiser, `installments` (de 1 a 12). O cliente precisa ter CPF ou CNPJ, telefone, CEP e número do endereço no cadastro; sem eles, a cobrança é recusada.
## Confira o status
> Linhas destacadas: 44-49
`paid` quer dizer aprovado. `unauthorized` quer dizer recusado: o pagamento continua em aberto e pode ser pago de novo. Para liberar o acesso, prefira o webhook `payment.approved`, confirmando com esta mesma consulta.
## Código
```js Node.js
import { publicEncrypt, constants } from 'node:crypto';
const BASE_URL = 'https://api.sandbox.cefispay.com.br/api/v1';
// 1. Gere uma encryption key (não usa o token da API)
const keyRes = await fetch(`${BASE_URL}/encryption_keys`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ merchant_id: process.env.NINEPAY_MERCHANT_ID }),
});
const key = await keyRes.json();
// 2. Encripte o cartão de teste (final 0 = aprovado no sandbox)
const card = JSON.stringify({
card_number: '5358732681618240',
card_holder_name: 'Maria Souza',
card_expiration_date: '05/2030',
card_cvv: '123',
});
const encrypted = publicEncrypt(
{ key: key.public_key, padding: constants.RSA_PKCS1_PADDING },
Buffer.from(card),
).toString('base64');
const cardHash = `${key.id}_${encrypted}`;
// 3. Cobre no cartão com o card hash
const paymentRes = await fetch(`${BASE_URL}/payments`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.NINEPAY_TOKEN}`,
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({
method: 'credit',
customer: { id: 315968 },
value: 15000, // R$ 150,00
installments: 3,
card_hash: cardHash,
}),
});
const { payment } = await paymentRes.json();
// 4. Confira o resultado
const detailsRes = await fetch(`${BASE_URL}/payments/${payment.id}`, {
headers: { Authorization: `Bearer ${process.env.NINEPAY_TOKEN}`, Accept: 'application/json' },
});
const { data } = await detailsRes.json();
console.log(data.status); // 'paid' (aprovado) ou 'unauthorized' (recusado)
```
---
# Criar um cliente e cobrar no PIX
Source: https://docs.ninepay.com.br/recipes/criar-cliente-e-cobrar-no-pix
Cadastre o cliente com POST /customers e gere uma cobrança PIX para ele com POST /payments.
## Aponte para o sandbox
> Linhas destacadas: 1-6
Todas as chamadas de teste vão para `https://api.sandbox.cefispay.com.br/api/v1`, com a chave de sandbox (prefixo `sk_hmlg_`) no header `Authorization: Bearer`. Guarde a chave em variável de ambiente e chame a API só do seu servidor.
## Cadastre o cliente
> Linhas destacadas: 8-18
`name` e `email` são obrigatórios; CPF (ou CNPJ) ajuda a identificar o pagador. Guarde o `id` retornado junto do usuário no seu sistema, para não criar o mesmo cliente duas vezes.
Se depois for cobrar no cartão, o cadastro também precisa de `phone`, `cep` e `number`.
## Crie a cobrança PIX
> Linhas destacadas: 20-30
Envie `method: "pix"`, o cliente e o valor em centavos. O `due_date` (`AAAA-MM-DD`) define o vencimento do PIX.
Para emitir um boleto, troque o `method` por `billet`: o `due_date` passa a ser obrigatório e a resposta traz também o `invoice_url`.
## Use o id e o uuid
> Linhas destacadas: 31-32
Use o `id` nas rotas autenticadas, como `GET /payments/{id}`, e o `uuid` no que é público, como o [checkout embutido](/docs/checkout-embutido). Para saber quando o cliente pagou, escute o webhook `payment.approved` (veja a recipe [Receber e validar webhooks](/recipes/receber-e-validar-webhooks)).
## Código
```js Node.js
const BASE_URL = 'https://api.sandbox.cefispay.com.br/api/v1';
const headers = {
Authorization: `Bearer ${process.env.NINEPAY_TOKEN}`,
'Content-Type': 'application/json',
Accept: 'application/json',
};
// 1. Cadastre o cliente
const customerRes = await fetch(`${BASE_URL}/customers`, {
method: 'POST',
headers,
body: JSON.stringify({
name: 'Maria Souza',
email: 'maria@exemplo.com.br',
cpf: '13690958725',
}),
});
const customer = await customerRes.json();
// 2. Crie a cobrança PIX para esse cliente
const paymentRes = await fetch(`${BASE_URL}/payments`, {
method: 'POST',
headers,
body: JSON.stringify({
method: 'pix',
customer: { id: customer.id },
value: 5000, // R$ 50,00, sempre em centavos
due_date: '2026-11-10',
}),
});
const { payment } = await paymentRes.json();
console.log(payment.id, payment.uuid);
```
## Resposta
```json
{
"customer": {
"id": 315968,
"name": "Maria Souza",
"email": "maria@exemplo.com.br",
"cpf": "13690958725"
},
"payment": {
"id": 1470491,
"uuid": "6f1c1a52-1d7e-4f43-a7a4-0a5a2b1c9e10",
"value": 5000,
"due_date": "2026-11-10T03:00:00.000000Z"
}
}
```
---
# Criar plano e assinatura recorrente
Source: https://docs.ninepay.com.br/recipes/criar-plano-e-assinatura
Crie um plano mensal, assine um cliente nele e mande o cliente para o checkout ativar a assinatura.
## Crie o plano
> Linhas destacadas: 3-15
O plano define valor (em centavos), periodicidade e métodos aceitos. Para cobrar todo mês, use `interval: 1` e `interval_type: "months"` (também aceita `days` e `years`). No sandbox, use `dunning_id: 1`, a régua de cobrança padrão.
Você também pode criar o plano pelo dashboard e usar só o `id` dele.
## Assine o cliente
> Linhas destacadas: 17-25
Toda assinatura liga um cliente a um plano. Se o cliente ainda não existe, crie antes com `POST /customers` (veja [Criar um cliente e cobrar no PIX](/recipes/criar-cliente-e-cobrar-no-pix)). Para aplicar desconto, envie os códigos de cupom em `coupon_codes`.
## Ative no checkout
> Linhas destacadas: 27-28
Com o `uuid` da assinatura, redirecione o cliente para a página de ativação. Ele só preenche os dados de pagamento. Em produção, o endereço é `https://checkout.ninepay.com.br/subscription//activate`.
Para cobrar dentro da sua própria página, veja o [checkout embutido](/docs/checkout-embutido). As mudanças da assinatura chegam pelo webhook `subscription.updated`.
## Código
```bash cURL
BASE_URL=https://api.sandbox.cefispay.com.br/api/v1
# 1. Crie o plano: R$ 49,90 por mês
PLAN_ID=$(curl -s -X POST "$BASE_URL/plan" \
-H "Authorization: Bearer $NINEPAY_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"name": "Plano Mensal",
"methods": ["credit", "pix", "billet"],
"value": 4990,
"interval": 1,
"interval_type": "months",
"dunning_id": 1
}' | jq -r '.id')
# 2. Assine o plano para um cliente já cadastrado
SUBSCRIPTION_UUID=$(curl -s -X POST "$BASE_URL/subscriptions" \
-H "Authorization: Bearer $NINEPAY_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d "{
\"customer\": { \"id\": $CUSTOMER_ID },
\"plan\": { \"id\": $PLAN_ID }
}" | jq -r '.subscription.uuid')
# 3. Mande o cliente para o checkout ativar a assinatura
echo "https://app.sandbox.cefispay.com.br/subscription/$SUBSCRIPTION_UUID/activate"
```
## Resposta
```json
{
"customer": {
"id": 315968,
"name": "Maria Souza",
"email": "maria@exemplo.com.br"
},
"subscription": {
"id": 205465,
"uuid": "8b2cad02-06f0-42be-84ac-101b23a1bb0d",
"amount": 4990,
"plan_id": 413
}
}
```
---
# Estornar um pagamento
Source: https://docs.ninepay.com.br/recipes/estornar-um-pagamento
Devolva ao cliente um pagamento pago no cartão ou no PIX e acompanhe o reembolso até ser concluído.
## Confira se pode estornar
> Linhas destacadas: 1
Só pode ser estornado o pagamento com `status: "paid"`, pago no cartão (`credit`) há menos de 350 dias ou no PIX (`pix`) há menos de 90 dias, e com saldo suficiente na sua conta. Boleto e baixa manual não têm estorno pela API. O campo `can_refund` do pagamento ajuda a conferir antes.
## Peça o estorno
> Linhas destacadas: 2-6
Envie o `id` do pagamento em `payment.id`. O estorno é sempre do valor integral e volta ao cliente pelo mesmo meio em que ele pagou.
## Acompanhe o reembolso
> Linhas destacadas: 8-11
O estorno do cartão costuma ser imediato: o pagamento passa a `reversed` e sai o webhook `payment.updated`. O do PIX pode ficar em processamento. Consulte o pagamento com `with[]=refunds`: o `status` de cada reembolso vai de `new` e `processing` para `completed` (devolvido) ou `failed`.
Enquanto um estorno está em `processing`, outro pedido para o mesmo pagamento é recusado.
## Código
```bash cURL
# 1. Peça o estorno do pagamento
curl -X POST https://api.sandbox.cefispay.com.br/api/v1/payment/reversal \
-H "Authorization: Bearer $NINEPAY_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{ "payment": { "id": 1470491 } }'
# 2. Acompanhe o reembolso
curl -g "https://api.sandbox.cefispay.com.br/api/v1/payments/1470491?with[]=refunds" \
-H "Authorization: Bearer $NINEPAY_TOKEN" \
-H "Accept: application/json"
```
---
# Receber e validar webhooks
Source: https://docs.ninepay.com.br/recipes/receber-e-validar-webhooks
Receba os eventos da NinePay, responda rápido, valide a assinatura, ignore entregas repetidas e confirme o pagamento na API antes de liberar o acesso.
## Exponha um endereço público
> Linhas destacadas: 8-11, 41
Cadastre a URL do seu servidor em **Integrações → Webhooks** no dashboard ou com `POST /automations` (veja [Webhooks](/docs/webhooks)). O endereço precisa ser público; use `https`. O formulário do webhook tem um envio de teste para cada evento.
## Leia o corpo cru e o evento
> Linhas destacadas: 12-14, 31
Cada entrega é um `POST` com JSON: `id` (o da entrega), `type` (o evento, como `payment.approved` ou `subscription.updated`), `data` (o recurso no mesmo formato da API) e `created_at`. Leia o corpo como bytes, sem fazer parse antes de validar: a assinatura é calculada sobre o corpo exatamente como chegou.
## Valide a assinatura
> Linhas destacadas: 16-29
Cada entrega de um webhook com segredo traz `X-Ninepay-Timestamp` e `X-Ninepay-Signature`. Calcule `sha256=` + HMAC-SHA256 de `"{timestamp}.{corpo cru}"`, com o segredo do webhook (`nep_whs_…`) como chave, e compare com o header em tempo constante. Recuse com 401 se não bater ou se o timestamp tiver mais de 5 minutos de diferença para o seu relógio. A assinatura muda a cada tentativa, então valide todas.
O segredo aparece uma vez só, ao criar o webhook ou ao clicar em **Gerar novo segredo**. Webhooks criados antes da assinatura não têm segredo, e não vêm assinados, até você clicar em **Gerar segredo** em **Integrações → Webhooks**.
## Responda em até 10 segundos
> Linhas destacadas: 33-34
Qualquer status fora de 2xx, ou a falta de resposta, conta como falha, e a entrega é repetida até 10 vezes, com intervalos crescentes. Responda primeiro e deixe o processamento pesado para depois (numa fila, por exemplo).
## Ignore entregas repetidas
> Linhas destacadas: 36-37
O `id` é o mesmo em todas as tentativas de uma entrega. Guarde os ids já processados para não liberar nada duas vezes. Os eventos também podem chegar fora de ordem.
## Confirme na API antes de liberar
> Linhas destacadas: 39-51
A assinatura prova que foi a NinePay quem enviou, mas não substitui a consulta. Trate o evento como um aviso: consulte `GET /payments/{id}` com o seu token e libere só se o `status` for `paid`. Assim, um `POST` forjado ou repetido para o seu endereço não libera nada.
## Código
```js Node.js
import { createServer } from 'node:http';
import { createHmac, timingSafeEqual } from 'node:crypto';
const BASE_URL = 'https://api.sandbox.cefispay.com.br/api/v1';
const processed = new Set(); // em produção, guarde no seu banco
createServer(async (req, res) => {
if (req.method !== 'POST' || req.url !== '/webhooks/ninepay') {
res.writeHead(404).end();
return;
}
const chunks = [];
for await (const chunk of req) chunks.push(chunk);
const rawBody = Buffer.concat(chunks); // corpo cru, antes de qualquer parse
// Valide a assinatura antes de confiar no evento
const timestamp = req.headers['x-ninepay-timestamp'] ?? '';
const signature = req.headers['x-ninepay-signature'] ?? '';
const expected = 'sha256=' + createHmac('sha256', process.env.NINEPAY_WEBHOOK_SECRET)
.update(`${timestamp}.`)
.update(rawBody)
.digest('hex');
const a = Buffer.from(signature);
const b = Buffer.from(expected);
const fresh = /^\d+$/.test(timestamp) && Math.abs(Date.now() / 1000 - Number(timestamp)) <= 300;
if (!fresh || a.length !== b.length || !timingSafeEqual(a, b)) {
res.writeHead(401).end();
return;
}
const event = JSON.parse(rawBody.toString('utf8'));
// Responda 2xx logo (em até 10 s) e processe depois
res.writeHead(200).end();
if (processed.has(event.id)) return; // a mesma entrega pode chegar de novo
processed.add(event.id);
if (event.type === 'payment.approved') {
// Mesmo com a assinatura válida, confirme o estado na API
const apiRes = await fetch(`${BASE_URL}/payments/${event.data.id}`, {
headers: {
Authorization: `Bearer ${process.env.NINEPAY_TOKEN}`,
Accept: 'application/json',
},
});
const { data: payment } = await apiRes.json();
if (payment.status === 'paid') {
// libere o acesso do cliente aqui
}
}
}).listen(3000);
```