Pular para o conteúdo

API Introduction

Environments, authentication, response and error formats, pagination and card hashes

Welcome to the NinePay API reference. This API is how you integrate your system with ours.

Our API is RESTful and all of its responses are in JSON, at the base endpoint:

Production
https://payments.cefis.com.br/api/v1/

The full list of endpoints, with parameters, responses and examples in several languages, is in the API Reference.

Environments

In addition to the production environment, a sandbox environment is available for integration testing. All communication with the sandbox environment must use the URL:

Sandbox
https://api.sandbox.cefispay.com.br/api/v1/

See how to request access in Test Environment.

Authentication

All requests that require authentication must send, in the Authorization header, the API token provided by our team, always for the intended environment, in the following format:

HTTP
Authorization: Bearer <token>

The token is a secret

Use the token only in your back end. Never put it in code that runs in the browser or in your customer's app.

Key prefixes (sk_prod_ and sk_hmlg_), creation, rotation and expiration are covered in Authentication.

Headers

We recommend setting the request headers correctly to work with the data types sent to and received from the API:

  • All requests must include the Content-Type: application/json header, unless the specific endpoint says otherwise.
  • All requests must include the Accept: application/json header, unless the specific endpoint says otherwise.

Responses

  • Resources come inside data: GET /customers/{id} responds with { "data": { ... } }.
  • Creations respond with 201. POST /payments responds with { "customer", "payment", "invoice_url" } (invoice_url only for bank slips) and POST /subscriptions responds with { "customer", "subscription" }.
  • Amounts are always in cents (integer): R$ 50.00 is 5000.

Errors

Every error has the same format:

JSON
{
  "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."
}

errors is only present on validation errors, with a list of messages per field. suggestion is present when there is one. Messages are returned in Portuguese. Keep the request_id when contacting support.

codeHTTPWhen
AUTHENTICATION_ERROR401Missing or invalid token
FORBIDDEN_ERROR403The resource does not belong to your company. On several routes, an id that does not exist also responds with 403, so as not to reveal which ids exist
COMPANYBLOCKED_ERROR403The account is suspended
RESOURCE_NOT_FOUND_ERROR404The resource does not exist
ROUTE_NOT_FOUND_ERROR404The route does not exist
METHOD_NOT_ALLOWED_ERROR405The method is not valid for the route (e.g. PUT /customers without the id)
INVALID_STATE_ERROR400The resource is not in a state that allows the action (e.g. canceling a payment that is already paid)
VALIDATION_ERROR422Invalid data; see errors
REFUND_NOT_ALLOWED422The payment cannot be refunded
TOO_MANY_ATTEMPTS429Too many requests; respect the Retry-After header
UNEXPECTED_ERROR500Our error; if it happens again, contact support with the request_id

Pagination

List endpoints accept page (starting at 1) and limit (items per page: 10 by default, from 1 to 100). The response contains data (the items), links and meta (current_page, last_page, per_page, total). To go through everything, increase page up to meta.last_page.

Dates

  • Calendar dates (due_date, next_payment) are sent as YYYY-MM-DD in requests.
  • In responses, date-time fields come in two formats: ISO 8601 in UTC (2026-10-27T03:00:00.000000Z, in the payment's due_date and ref_date) and YYYY-MM-DD HH:MM:SS in Brasília time (created_at and updated_at). Parse each field according to its format.

Identifiers

Every resource has a numeric id and a uuid. Use the id in authenticated routes and the uuid in everything that is public (the payment link, the checkout and the bank slip PDF).

Card hash

A card hash is an encrypted version of all of your customer's card data. It is the safest way to send your customer's card data directly to us. Below we explain how it works and how to obtain a hash from the data entered by the customer.

Front end only

This flow must run on the front end, whether web or mobile. Your customer's card data must never be sent to your back end; the card hash, however, can be sent to the back end safely.

Generating an encryption key

The encryption key is an RSA public key used to encrypt the card data. This key can be used only once: whenever you need to encrypt a new card, generate a new encryption key.

To generate an encryption key, make a POST request to the API's /encryption_keys route, sending your merchant_id as a parameter. It does not use the API token (never put it on the front end): the merchant_id identifies your account, and a merchant_id that does not exist responds with 401.

The request must have this format:

cURL
curl -X POST https://payments.cefis.com.br/api/v1/encryption_keys \
  -H 'Content-Type: application/json' \
  -d '{"merchant_id":"SEU_MERCHANT_ID"}'

In response you will receive a JSON object in the following format:

JSON
{
  "id": 1111,
  "public_key": "-----BEGIN PUBLIC KEY-----\n ... \n-----END PUBLIC KEY-----\n",
  "ip_address": "000.000.000.000",
  "created_at": "2017-07-03"
}

Encrypting the card data

To encrypt the card data, first format it correctly: create a JSON string containing all the card data in the following format:

JSON
{"card_number":"1111111111111111","card_holder_name":"Jose Silva","card_expiration_date":"11/2021","card_cvv":"111"}

Then RSA-encrypt this string using the public key (public_key) generated in the previous step, with PKCS1 padding.

After encrypting the data, convert the result to base64. You will have something like this:

Text
GprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==

The last step is to concatenate the id of your encryption key (received in the response to the previous request) with the base64 string that represents the card data, as follows:

Text
encryption_key_id + "_" + base64_encrypted_card

The result is your card hash:

Text
1111_GprWNDlg+MKGgtr6y9wJgz7oOUxGuhhdX3EwydmoOvb+yNDWrjDKktDtWicReOrvSo0u5rsNvCqBFjyoMfaRXn4Qq3KdV8vuuFXubb4FT3OcSSVpu6ddaOjm2tf82+GKjdCy54Lgw4T0m9mWdLPveh/zkYP0+4lhHCFhBKX5EqBdR4918wP5oUV1KpzV4V94ldSA+Cy2n1NUxyUiSnv87H2m+HkdqKDIcX9X8KEtUmorC/EjTPzoeEdpRdj8t3ThcL73mirJvDcYthSdT/ADyaFQ2hMRMkKEVOQjUYMn76vzWyQkqsZ+HVQlxQMOBVHPh5yfrmi1HAVd1jLQuOK8wQ==

Done: your customer's card data is now in a safe format to travel over the network and can be sent to your back end to continue the flow (in the card_hash field of POST /payments).

Card hash validity

Each card hash can be used only once and is valid for at most 30 minutes after the encryption key is generated. If you need to use the card more than once, make a request to the cards route and save the card linked to the user who owns it: you will receive a unique ID that can be used in new transactions with the same card.

Support

Questions about the integration: ti@ninepay.com.br. Terms of use: bit.ly/cefispay-contrato.