Introduction
Hokodo provides a set of API endpoints to facilitate Deferred Payments, also known as credit terms, or "Buy Now, Pay Later" (BNPL) for B2B platforms, such as marketplaces or e-commerce sites.
This reference documentation details how developers may use Hokodo to implement credit terms into their customer journey, from checking whether a customer can be eligible for credit terms, to submitting a customer's orders to Hokodo. Hokodo APIs are organized around REST, with predictable, resource-oriented URLs, and use HTTP response codes to indicate API errors.
Our API expects incoming data to be valid JSON objects with requests
containing the header Content-Type: application/json
, unless explicitly stated otherwise.
All responses of the API, including errors, are in JSON, except for some endpoints returning PDF documents, Excel files or CSV files, that will be clearly indicated as such.
You can view request/response examples in the dark area to the right, and you can switch between raw representation and curl command with tabs in the top right.
The base URL of the API in the sandbox (see environments) is https://api-sandbox.hokodo.co/
API Guide
This API reference is a comprehensive description of the technical behaviour of Hokodo's BNPL API.
It is intended to be read alongside our API Guide, which should be your primary resource for integrating Hokodo's BNPL solution.
Glossary
In the document, we will use the following terms, with a specific meaning:
- Order: An order represents an instance of buying or selling something on your platform. An order consists of a basket of order items, plus details about who the company making the purchase is. Orders can be paid for at the time of the order or benefit from credit terms. Fundamentally, Hokodo's solution gives you an easier way to offer credit terms to your customers when they transact on your platform.
- Payment Offer: When a customer reaches the check-out, you will need to check if that particular order is eligible for Deferred Payment. To do this you request a Payment Offer. The Payment Offer is a list of different payment terms which are available for that order (if any), for example, "Pay in 30 days" or "Pay in instalments". The payment offer defines the specific date(s) on which repayment will be due along with other information such as the cost of those particular payment terms. You will typically want to display each of the available Payment Offers as different payment options in your check-out, which customers can then click on to select.
- Deferred Payment: Once a customer clicks on a particular Payment option (such as Pay in 30 days), we will create a Deferred Payment object. This represents the financing that Hokodo will provide to enable that order to be completed on credit terms. The Deferred Payment is analogous to a loan, and it moves through various states from the application process (when the customer first clicks on it, through to being confirmed and ultimate being settled).
Organisations and Users
Because Hokodo focuses on B2B sales, the buyers on your platform will consist of Companies, who have employees, and those employees may be organised into teams or departments. Hokodo deals with this complexity through the concept of Organisations and Users.
A User is an individual employee at a company. An Organisation is a group of Users who are all able to see or take action on that company's orders on your platform. Each Organisation must be associated with a Company.
In many cases the company will just have a single Organisation, and any employees of the company (Users) will be members of that Organisation. In this case, any one of those Users will be able to see or take actions on any of the company's orders on your platform. For example, if a member of the Organisation has set up a direct debit mandate, then any other member of that Organisation can make purchases using the mandate.
In other cases (for larger companies), there may be several Organisations - perhaps one associated to each department in the company. In this case, Users can only see the orders associated with their Organisation.
Authorization
To authentify pass the correct header with each request:
GET /v1/me HTTP/1.1
Authorization: Token <your_api_key>
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/me/ \
--header "Authorization: Token <your_api_key>"
Make sure to replace
<your_api_key>
with your API key from https://sandbox.hokodo.co.
Use your secret key in your API requests. You can manage your keys in your Developer dashboard. Be sure to keep your key secure and do not share it in publicly-accessible areas, such as GitHub, in your client-side Javascript code, etc.
Authorization to the API is done by providing the key in Authorization header
preceded by Token
keyword. The API key can also be provided as user with no
password through HTTP Basic Auth.
All API requests must be made over HTTPS. Calls made over plain HTTP or without proper authentication will fail.
Testing the API
Please make sure to test your integration thoroughly in our sandbox before going live. After registering, you will be given your test API keys. Those are safe to use for development. When you are ready, make sure to replace those keys with live ones.
While testing, the API will not return real credit approvals and limits. If you want to simulate how well we can cover your clients, please do not hesitate to get in touch with our team at support@hokodo.co.
API versioning
The BNPL API is in version v1. Your feedback is most appreciated for any improvement.
Backwards compatible changes are made regularly to improve the API. You can find the changelog in the partner dashboard.
Pagination
For example to get 10 orders starting with the 51st order:
GET /v1/payment/orders/?limit=10&offset=50 HTTP/1.1
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/payment/orders/?limit=10&offset=50 \
--header "Authorization: Token <your_api_key>"
The answer is a JSON looking like this:
{
"count": 95, # Total number of orders
"next": "http://api-sandbox.hokodo.co/v1/payment/orders/?limit=10&offset=60",
"previous": null,
"results": [
{
... # 51st order in the list
},
{
... # 52nd order in the list
}
...
]
}
The API returns paginated results, for list endpoints where the response might contain many items in a large list. By default, the number of items returned is 25.
You can control the page size and position by using the query parameters
limit
and offset
. limit
controls the number of items displayed, offset
the index of the first item of the list, starting from 0. The defaults if no
value is passed are thus offset=0
and limit=25
.
See examples on the right.
Expansion
For example let's consider the following request:
GET /v1/payment/offers/offer-kEFDnwu8cnkETeagWAcqF4 HTTP/1.1
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/payment/offers/offer-kEFDnwu8cnkETeagWAcqF4 \
--header "Authorization: Token <your_api_key>"
It's returning the following JSON response (compacted for the example):
{
"url": "http://api-sandbox.hokodo.co/v1/payment/offers/offer-kEFDnwu8cnkETeagWAcqF4",
"id": "offer-kEFDnwu8cnkETeagWAcqF4",
"order": "order-TiehJCGZmFRkKoL8NsM3d6",
"status": "accepted"
... # Other payment offer fields
}
We can use
?expand=order
for example:
GET /v1/payment/offers/offer-kEFDnwu8cnkETeagWAcqF4?expand=order HTTP/1.1
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/payment/offers/offer-kEFDnwu8cnkETeagWAcqF4?expand=order \
--header "Authorization: Token <your_api_key>"
As a response we get:
{
"url": "http://api-sandbox.hokodo.co/v1/payment/offers/offer-kEFDnwu8cnkETeagWAcqF4",
"id": "quo-kEFDnwu8cnkETeagWAcqF4",
"order": {
"id": "order-TiehJCGZmFRkKoL8NsM3d6"
... # Other order fields
},
"status": "accepted"
... # Other payment offer fields
}
The API returns some items as API identifiers. The designated resource can be
expanded, meaning that the identifier is replaced in the response with a dictionary
representing the resource itself. You can control which field is expanded using the
query parameter expand
. Expected value is a comma separated list of field names,
for example ?expand=order,payment
.
Note: At the moment, only read requests can use expansion. You can't use resource expansion for requests where you create and modify resources.
See examples on the right.
Environments
Test environment (aka Sandbox)
- Register at: https://sandbox.hokodo.co
- API base URL:
https://api-sandbox.hokodo.co/
This is the test environment for our API clients, where you can integrate your own software with our API without consequences. It will always run the same version(s), expect the same request format and return the same response format as the production environment.
Data such as credit scores or payment offers will not be real however, and no payment is provided. Non-sensitive data, such as companies search, will be as close as possible to the production data.
Production
- Apply at: https://www.hokodo.co/contact
- API base URL:
https://api.hokodo.co/
This is the live, production environment, where:
- the data is real,
- the payment offers provided are real and binding for us,
- payments happen and money changes hands (or at least bank accounts).
Data formats
Countries
Requests
- buyer countries
GET /v1/countries/debtor HTTP/1.1
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/countries/debtor
Response
200 Ok
Content-Type: application/json
[
{
"code": "GB",
"name": "United Kingdom"
},
{
"code": "FR",
"name": "France"
}
]
Where a country input field is required by the API, you can use either the ISO 3166-1 alpha-2 code or the country's name. See below on how to obtain a full list of accepted countries.
- Buyer countries:
/v1/countries/debtor
Obtain a list of valid countries for a buyer/customer.
Dates and times
When a date, or date and time field is required by the API, it is expected in ISO 8601 notation, for example:
Type | Format | Example |
---|---|---|
Date | yyyy-mm-dd | 2018-10-31 |
Datetime | yyyy-mm-ddThh:mm:ss.ffffff | 2018-10-31T16:53:00.12345 |
Datetime UTC | yyyy-mm-ddThh:mm:ss.ffffffZ | 2018-10-31T16:53:00.12345Z |
For order issue and due dates for example, there is no time associated and the
API expects only a date, no time nor timezone. Be careful if you are internally
converting a datetime with timezone to a date, e.g. 2018-10-31T00:00:00+02:00
could become 2018-10-30T22:00:00Z
when converted to UTC and then 2018-10-30
in the request to the API, which wouldn't fit the user input.
Currencies
When a currency field is used by the API, it is an ISO 4217 code,
such as GBP
, EUR
or USD
.
Amounts
When a money amount is expected or returned by the API, it is always in minor units, ie cents. For example:
- £50.00 would be represented as
5000
, - £12.34 would be represented as
1234
.
Rate Limiting
Some endpoints (e.g. Credit Limits) implement rate limiting and may return an HTTP 429, if too many requests happen too quickly.
Please contact your Customer Success Manager or Solution Engineer for more detail if you are thinking of running large batches.
Example: an endpoint hitting a rate limit
Response
429 Too Many Requests
Content-Type: application/json
Retry-After: 60
{
"detail": "Request was throttled. Expected available in 60 seconds."
}
Idempotent Requests
The API supports idempotent requests on a selection of endpoints for safely retrying requests without performing the operation twice.
To perform an idempotent request provide the optional Idempotency-Key: <key>
header with a value that must be unique per request.
If a request is repeated with the same key
, it will return the same data and status code.
We recommend choosing a randomly generated string with high entropy, such as a UUID v4. This will avoid accidentally re-using the same key for different requests, resulting in an HTTP 400 error.
Example: repeating a request
Request 1
GET /v1/payment/deferred_payments/defpay-bqRyGIGaORKiK8bhMVPirp/capture HTTP/1.1
Authorization: Token <your_api_key>
Idempotency-Key: 33871f6b-ff2f-4de3-9e10-ff42ef7af553
{
"amount": 100000
}
curl --request POST \
--url https://api-sandbox.hokodo.co/v1/payment/deferred_payments/defpay-bqRyGIGaORKiK8bhMVPirp/capture \
--header "Idempotency-Key: 33871f6b-ff2f-4de3-9e10-ff42ef7af553" \
--header "Authorization: Token <your_api_key>" \
--data-binary '{"amount": 100000}'
Response 1
201 CREATED
Content-Type: application/json
{
"created": "2023-05-30T15:22:44.788858Z",
"type": "capture",
"amount": 100000,
"currency": "GBP",
"metadata": {},
"changes": {
"authorisation": -10000,
"protected_captures": 10000,
"unprotected_captures": 0,
"refunds": 0,
"voided_authorisation": 0,
"expired_authorisation": 0,
"clawback": 0
}
}
Request 2
GET /v1/payment/deferred_payments/defpay-bqRyGIGaORKiK8bhMVPirp/capture HTTP/1.1
Authorization: Token <your_api_key>
Idempotency-Key: 33871f6b-ff2f-4de3-9e10-ff42ef7af553
{
"amount": 100000
}
curl --request POST \
--url https://api-sandbox.hokodo.co/v1/payment/deferred_payments/defpay-bqRyGIGaORKiK8bhMVPirp/capture \
--header "Idempotency-Key: 33871f6b-ff2f-4de3-9e10-ff42ef7af553" \
--header "Authorization: Token <your_api_key>" \
--data-binary '{"amount": 100000}'
Response 2
201 CREATED
Content-Type: application/json
{
"created": "2023-05-30T15:22:44.788858Z",
"type": "capture",
"amount": 100000,
"currency": "GBP",
"metadata": {},
"changes": {
"authorisation": -10000,
"protected_captures": 10000,
"unprotected_captures": 0,
"refunds": 0,
"voided_authorisation": 0,
"expired_authorisation": 0,
"clawback": 0
}
}
In the example on the right, the same request is made twice. Each time, the same Idempotency-Key
and request body is used.
The first request will create a new capture
deferred payment event for deferred payment defpay-bqRyGIGaORKiK8bhMVPirp
and return a 201 CREATED
.
Making a second request with the same idempotency key will not create a new event. It will return the event created in the original request, with the original HTTP status code.
Example: accidental key re-use
Request 1: Different event type
GET /v1/payment/deferred_payments/defpay-bqRyGIGaORKiK8bhMVPirp/void HTTP/1.1
Authorization: Token <your_api_key>
Idempotency-Key: 33871f6b-ff2f-4de3-9e10-ff42ef7af553
{
"amount": 100000
}
curl --request POST \
--url https://api-sandbox.hokodo.co/v1/payment/deferred_payments/defpay-bqRyGIGaORKiK8bhMVPirp/void \
--header "Authorization: Token <your_api_key>" \
--header "Idempotency-Key: 33871f6b-ff2f-4de3-9e10-ff42ef7af553" \
--data-binary '{"amount": 100000}'
Response 1
400 BAD REQUEST
Content-Type: application/json
{
"error": "Duplicate `Idempotency-Key` [33871f6b-ff2f-4de3-9e10-ff42ef7af553] has been used to create a `capture` event, the key cannot be used to create a `void` event."
}
Request 2: Different amount
GET /v1/payment/deferred_payments/defpay-bqRyGIGaORKiK8bhMVPirp/capture HTTP/1.1
Authorization: Token <your_api_key>
Idempotency-Key: 33871f6b-ff2f-4de3-9e10-ff42ef7af553
{
"amount": 50
}
curl --request POST \
--url https://api-sandbox.hokodo.co/v1/payment/deferred_payments/defpay-bqRyGIGaORKiK8bhMVPirp/capture \
--header "Authorization: Token <your_api_key>" \
--header "Idempotency-Key: 33871f6b-ff2f-4de3-9e10-ff42ef7af553" \
--data-binary '{"amount": 50}'
Response 2
400 BAD REQUEST
Content-Type: application/json
{
"error": "Duplicate `Idempotency-Key` [33871f6b-ff2f-4de3-9e10-ff42ef7af553] cannot be used to create an event with a different `amount`."
}
Any other use of the same key, for instance on a different endpoint with a slightly different request, will result in a 400
.
In the first example on the right, we are using the same Idempotency-Key
as before, but we are using it to create a void
instead of a capture
. The result is an HTTP 400 because this is not the same request as before.
In the second example on the right, we are using the same Idempotency-Key
as before, but capturing a different amount
. The result is an HTTP 400 because this is not the same request as before.
Companies
Companies represent the legal entities associated with your customers. To be able to provide accurate credit approval and limits, and payment plans, we need to properly identify the companies.
If you already store a unique company identifier such as a Companies House number (UK) or SIREN (France) then you can use our Companies endpoint to obtain the Hokodo ID for the company.
More commonly, however, merchants simply store a free text name for their customers' companies. Because there can often be many companies with similar sounding names (including different subsidiaries of the same parent), we typically recommend adopting the following process to make sure you are supplying the correct company identifiers:
- presenting your user with text box(es), where they can enter their company's name, and/or address, and/or registration number,
- using that information in our company search API, to obtain a list of companies which are potential matches to the text you supplied.
- asking the user to pick among the choices our company search API has returned.
Companies endpoints
POST /v1/companies/search
GET /v1/companies/<company_id>
Company object
{
"url": "https://api-sandbox.hokodo.co/v1/companies/co-bqRyKAGaFrEEN8JMjWJiqk",
"id": "co-bqRyKAGaFrEEN8JMjWJiqk",
"name": "Hokodo Ltd",
"creation_date": "2018-02-20",
"status": "Active",
"legal_form": "Private limited with share capital",
"country": "GB",
"address": "35 Kingsland Road, London, E2 8AA",
"city": "London",
"postcode": "E2 8AA",
"email": "",
"phone": "",
"sectors": [
{
"system": "SIC2007",
"code": "64999"
},
{
"system": "SIC2007",
"code": "62012"
},
{
"system": "SIC2007",
"code": "66220"
}
],
"identifiers": [
{
"idtype": "reg_number",
"country": "GB",
"value": "11215527"
}
]
}
field | type | description |
---|---|---|
url | string | API endpoint to access the company |
id | string(uuid) | API unique identifier for the company |
name | string | Company name |
creation_date | date | Date of inception of the company |
status | string | Current status of the company. You are generally interested about Active or ACT companies |
legal_form | string | Legal form of the company. The list of possible legal forms varies from country to country. |
country | country | Registered address: country code |
address | string | Registered address: full postal address |
city | string | Registered address: city name |
postcode | string | Registered address: postcode |
string | Contact email address for the company | |
phone | string | Contact phone number for the company |
sectors | list | The list of sectors the company operate in. |
sectors[*][system] | string | The system of reference to interpret the code (SIC2007 in UK, NAF_2008 in FR) |
sectors[*][code] | string | Sector code in the given system |
identifiers | list | The list of official identifiers know for this company, e.g. Companies House registration number, VAT number, etc. |
identifiers[*][id_type] | string | The type of identifier (reg_number for a registration number, lei for an identifier of the Global LEI System, vat_number for a tax identifier) |
identifiers[*][country] | country | Country in which the identifier is relevant when it applies. Can be blank. |
identifiers[*][value] | string | Identifier |
Company search
Request
POST /v1/companies/search HTTP/1.1
Content-Type: application/json
{
"name": "Hokodo Ltd",
"country": "GB"
}
curl --request POST \
--url https://api-sandbox.hokodo.co/v1/companies/search \
--header "Content-Type: application/json" \
--data-binary '{
"name": "Hokodo Ltd",
"country": "GB"
}'
Responses
- regular response
200 OK
Content-Type: application/json
{
"matches": [
{
"url": "https://api-sandbox.hokodo.co/v1/companies/co-EWzoaRqbvsdq8FW7dB6evL",
"id": "co-EWzoaRqbvsdq8FW7dB6evL",
"country": "GB",
"name": "HOKODO LTD",
"address": "35 Kingsland Road, London, United Kingdom, E2 8AA",
"city": "London",
"postcode": "E2 8AA",
"legal_form": "",
"sectors": [],
"creation_date": "2018-02-20",
"identifiers": [
{
"idtype": "reg_number",
"country": "GB",
"value": "11215527"
}
],
"email": "",
"phone": "",
"status": "Undefined",
"confidence": null
},
{
"url": "https://api-sandbox.hokodo.co/v1/companies/co-JbTDrzejAhRafYrKSFEGi4",
"id": "co-JbTDrzejAhRafYrKSFEGi4",
"country": "GB",
"name": "Hokodo Services Ltd",
"address": "35 Kingsland Road, London, E2 8AA",
"city": "London",
"postcode": "E2 8AA",
"legal_form": "Private limited with share capital",
"sectors": [],
"creation_date": "2018-05-09",
"identifiers": [
{
"idtype": "reg_number",
"country": "GB",
"value": "11351988"
}
],
"email": "",
"phone": "",
"status": "Active",
"confidence": null
}
]
}
- no results
200 OK
Content-Type: application/json
{
"matches": []
}
- error response (
country
field missing)
{
"country": [
"This field is required."
]
}
- error response (
name
andreg_number
fields missing)
400 Bad Request
Content-Type: application/json
{
"non_field_errors": [
"Not enough information to identify company. Provide at least country and either name or registration number."
]
}
Search for a company by country, name, registration number if available. Country is mandatory, and one of name or registration number must be provided. The API will try to find the best match and return a list of potential matches.
field | description | requirement |
---|---|---|
country | Country the company is registered in | required |
name | Name of the company | required * |
reg_number | Registration number in country | required * |
address | Address of the company | optional |
(at least one of fields, marked with * is required)
Errors:
code | description |
---|---|
400 | a required field is missing |
View Company
Request
GET /v1/companies/{company_id} HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/companies/{company_id} \
--header "Authorization: Token <your_api_key>" \
--header "Content-Type: application/json"
Responses
- regular response
200 OK
Content-Type: application/json
{
"url": "https://api-sandbox.hokodo.co/v1/companies/co-EWzoaRqbvsdq8FW7dB6evL",
"id": "co-EWzoaRqbvsdq8FW7dB6evL",
"country": "GB",
"name": "HOKODO LTD",
"address": "35 Kingsland Road, London, United Kingdom, E2 8AA",
"city": "London",
"postcode": "E2 8AA",
"legal_form": "",
"sectors": [],
"creation_date": "2018-02-20",
"identifiers": [
{
"idtype": "reg_number",
"country": "GB",
"value": "11215527"
}
],
"email": "",
"phone": "",
"status": "Undefined"
}
- not found
404 Not Found
Content-Type: application/json
{
"detail": "Not found."
}
Look up a previously found company.
Errors:
code | description |
---|---|
404 | the company_id is probably invalid, and the company has not been found |
Sole traders
Sole Traders represent unregistered entities associated with your customers. To be able to provide accurate credit approval, limits, and payment plans, we need to properly identify the company and the sole trader (proprietor).
Commonly, merchants store a free text name for their customers' sole trading businesses. Because there can often be many sole traders with similar sounding names, and, as unregistered businesses sole traders will generally not have a government issued unique identifier (registered companies will have a registration number for instance) we typically recommend adopting the following process to make sure you are supplying the correct information for sole traders:
- presenting your user with text box(es), where they can enter their owner / proprietor's name and address
- presenting your user with text boxes where they can enter their company's name and address
- using that information to create a
SoleTrader
on the Hokodo platform
Hokodo require both company and proprietor data to provide servers for the sole trader, without complete data Hokodo will not be able to accurately credit score the company.
By default, only certain types of companies can be offered Buy Now Pay Later by Hokodo. If a significant portion of your users are sole traders, get in touch with us to enable that function for you.
You will be able to create SoleTrader
objects, which are an extension of the Company
objects.
Sole trader endpoints
POST /v1/soletraders
GET /v1/soletraders
GET /v1/soletraders/<soletrader_id>
PATCH /v1/soletraders/<soletrader_id>
SoleTrader object
{
"id": "co-YuNEQ4nqA6Yto9QQUBnopW",
"soletrader_id": "st-eE4un8TnDNjx9Uac2DVa6N",
"owner": "user-sVr7a58Smbfqbo8cVpjEV6",
"unique_id": "0d201ab1-46df-4274-8c90-256eaa66c135",
"vat_number": "15141312",
"trading_name": "The Dogfather 21",
"trading_address": "123 Commercial St, Shoreditch",
"trading_address_city": "London",
"trading_address_postcode": "EC2A 8AB",
"trading_address_country": "GB",
"proprietor_name": "John John",
"proprietor_address_line1": "Flat 5",
"proprietor_address_line2": "10 Residential Street",
"proprietor_address_line3": "Hackney",
"proprietor_address_city": "London",
"proprietor_address_postcode": "EC2 8AA",
"proprietor_address_country": "GB",
"date_of_birth": "1969-12-31"
}
field | type | flags | description |
---|---|---|---|
id | string(uuid) | read-only | Unique company identifier for the object. To be used where a Company identifier is required, such as creditor in a transaction. |
soletrader_id | string(uuid) | read-only | Unique identifier for the object. To be used where a SoleTrader identifier is required. |
owner | string(uuid) | required | Unique identifier of the user associated to the sole trader. |
unique_id | string | required | Unique identifier of the sole trader at your platform |
vat_number | string | optional | VAT number of the sole trader if available. |
trading_name | string | required | Company's name |
trading_address | string | required | Company's full address |
trading_address_city | string | required | Company's city |
trading_address_postcode | string | required | Company's postcode |
trading_address_country | country | required | Company's country |
proprietor_name | string | required | Proprietor's name |
proprietor_address_line1 | string | required | Proprietor's address including house number |
proprietor_address_line2 | string | required | Proprietor's address |
proprietor_address_line3 | string | optional | Proprietor's address |
proprietor_address_city | string | required | Proprietor's city |
proprietor_address_postcode | string | required | Proprietor's postcode |
proprietor_address_country | country | required | Proprietor's country |
date_of_birth | date | required | Proprietor's date of birth (e.g. 1969-12-31 ). Accepted format: YYYY-MM-DD . |
Create a sole trader
Request
POST /v1/soletraders HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
{
"owner": "user-KZcuB2oT6BPTjmQJiHm7ha",
"trading_name": "The Dogfather",
"trading_address": "123 Commercial St, Shoreditch",
"trading_address_city": "London",
"trading_address_postcode": "EC2A 8AB",
"trading_address_country": "GB",
"proprietor_name": "John John",
"proprietor_address_line1": "Flat 5",
"proprietor_address_line2": "10 Residential Street",
"proprietor_address_line3": "Hackney",
"proprietor_address_city": "London",
"proprietor_address_postcode": "EC2 8AA",
"proprietor_address_country": "GB",
"vat_number": "15141312",
"unique_id": "0d201ab1-46df-4274-8c90-256eaa66c136",
"date_of_birth": "1969-12-31"
}
curl --request POST
--url https://api-sandbox.hokodo.co/v1/soletraders \
--header "Authorization: Token <your_api_key>" \
--header 'Content-Type: application/json' \
--data-binary "{
\"owner\": \"user-KZcuB2oT6BPTjmQJiHm7ha\",
\"trading_name\": \"The Dogfather\",
\"trading_address\": \"123 Commercial St, Shoreditch\",
\"trading_address_city\": \"London\",
\"trading_address_postcode\": \"EC2A 8AB\",
\"trading_address_country\": \"GB\",
\"proprietor_name\": \"John John\",
\"proprietor_address_line1\": \"Flat 5\",
\"proprietor_address_line2\": \"10 Residential Street\",
\"proprietor_address_line3\": \"Hackney\",
\"proprietor_address_city\": \"London\",
\"proprietor_address_postcode\": \"EC2 8AA\",
\"proprietor_address_country\": \"GB\",
\"vat_number\": \"15141312\",
\"unique_id\": \"0d201ab1-46df-4274-8c90-256eaa66c136\",
\"date_of_birth\": \"1969-12-31\"
}"
Responses
- regular response
201 Created
Content-Type: application/json
{
"id": "co-5oh3SJKQBaKMov9PYR7BkA",
"owner": "user-mECT3e5n9i7gVGrbn2Pd38",
"soletrader_id": "st-Vdrisa6GZnSp49ZaqMDssR",
"trading_name": "The Dogfather",
"trading_address": "123 Commercial St, Shoreditch",
"trading_address_city": "London",
"trading_address_postcode": "EC2A 8AB",
"trading_address_country": "GB",
"proprietor_name": "John John",
"proprietor_address_line1": "Flat 5",
"proprietor_address_line2": "10 Residential Street",
"proprietor_address_line3": "Hackney",
"proprietor_address_city": "London",
"proprietor_address_postcode": "EC2 8AA",
"proprietor_address_country": "GB",
"vat_number": "15141312",
"unique_id": "0d201ab1-46df-4274-8c90-256eaa66c136",
"date_of_birth": "1969-12-31"
}
- error response (example)
400 Bad Request
Content-Type: application/json
{
"owner": [
"Invalid pk \"user-KZcuB2oT6BPTjmQJiHm7hb\" - object does not exist."
],
"unique_id": [
"sole trader with this Unique identifier on platform already exists."
]
}
To create a sole trader, you create a SoleTrader
object.
Errors
errors | description |
---|---|
400 | a required field is missing or some fields have incorrect values |
List sole traders
Request
POST /v1/soletraders HTTP/1.1
Authorization: Token <your_api_key>
curl --request POST
--url https://api-sandbox.hokodo.co/v1/soletraders \
--header "Authorization: Token <your_api_key>"
Response
200 Ok
Content-Type: application/json
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": "co-5oh3SJKQBaKMov9PYR7BkA",
"owner": "user-mECT3e5n9i7gVGrbn2Pd38",
"soletrader_id": "st-Vdrisa6GZnSp49ZaqMDssR",
"trading_name": "The Dogfather",
"trading_address": "123 Commercial St, Shoreditch",
"trading_address_city": "London",
"trading_address_postcode": "EC2A 8AB",
"trading_address_country": "GB",
"proprietor_name": "John John",
"proprietor_address_line1": "Flat 5",
"proprietor_address_line2": "10 Residential Street",
"proprietor_address_line3": "Hackney",
"proprietor_address_city": "London",
"proprietor_address_postcode": "EC2 8AA",
"proprietor_address_country": "GB",
"vat_number": "15141312",
"unique_id": "0d201ab1-46df-4274-8c90-256eaa66c136",
"date_of_birth": "1969-12-31"
}
]
}
List all sole traders, created by your platform
View sole trader
Request
GET /v1/soletraders/<soletrader_id> HTTP/1.1
Authorization: Token <your_api_key>
curl --request GET
--url https://api-sandbox.hokodo.co/v1/soletraders/co-5oh3SJKQBaKMov9PYR7BkA \
--header "Authorization: Token <your_api_key>"
Response
200 Ok
Content-Type: application/json
{
"id": "co-5oh3SJKQBaKMov9PYR7BkA",
"owner": "user-mECT3e5n9i7gVGrbn2Pd38",
"soletrader_id": "st-Vdrisa6GZnSp49ZaqMDssR",
"trading_name": "The Dogfather",
"trading_address": "123 Commercial St, Shoreditch",
"trading_address_city": "London",
"trading_address_postcode": "EC2A 8AB",
"trading_address_country": "GB",
"proprietor_name": "John John",
"proprietor_address_line1": "Flat 5",
"proprietor_address_line2": "10 Residential Street",
"proprietor_address_line3": "Hackney",
"proprietor_address_city": "London",
"proprietor_address_postcode": "EC2 8AA",
"proprietor_address_country": "GB",
"vat_number": "15141312",
"unique_id": "0d201ab1-46df-4274-8c90-256eaa66c136",
"date_of_birth": "1969-12-31"
}
Retrieve a single sole trader, created by your platform
Errors
errors | description |
---|---|
404 | the soletrader_id is probably invalid, the sole trader has not been found |
Modify sole trader
Request
PATCH /v1/soletraders/<soletrader_id> HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
{
"trading_name": "The Catfather",
"proprietor_name": "Johnny John"
}
curl --request PATCH
--url https://api-sandbox.hokodo.co/v1/soletraders/co-5oh3SJKQBaKMov9PYR7BkA \
--header "Authorization: Token <your_api_key>" \
--header 'Content-Type: application/json' \
--data-binary "{
\"trading_name\": \"The Catfather\",
\"proprietor_name\": \"Johnny John\"
}"
Response
200 Ok
Content-Type: application/json
{
"id": "co-5oh3SJKQBaKMov9PYR7BkA",
"owner": "user-mECT3e5n9i7gVGrbn2Pd38",
"soletrader_id": "st-Vdrisa6GZnSp49ZaqMDssR",
"trading_name": "The Catfather",
"trading_address": "123 Commercial St, Shoreditch",
"trading_address_city": "London",
"trading_address_postcode": "EC2A 8AB",
"trading_address_country": "GB",
"proprietor_name": "Johnny John",
"proprietor_address_line1": "Flat 5",
"proprietor_address_line2": "10 Residential Street",
"proprietor_address_line3": "Hackney",
"proprietor_address_city": "London",
"proprietor_address_postcode": "EC2 8AA",
"proprietor_address_country": "GB",
"vat_number": "15141312",
"unique_id": "0d201ab1-46df-4274-8c90-256eaa66c136",
"date_of_birth": "1969-12-31"
}
Modify previously created sole trader
Errors
errors | description |
---|---|
404 | the soletrader_id is probably invalid, the sole trader has not been found |
400 | a required field is missing or some fields have incorrect values |
Organisations
Because Hokodo focuses on B2B sales, the buyers on your platform will consist of Companies, who have employees, and those employees may be organised into teams or departments. Hokodo deals with this complexity through the concept of Organisations and Users. A User is an individual employee at a company. An Organisation is a group of Users who are all able to see or take action on that company's orders on your platform. Each Organisation must be associated with a Company.
Organisation endpoints
POST /v1/organisations
GET /v1/organisations
GET /v1/organisations/<organisation_id>
PATCH /v1/organisations/<organisation_id>
DELETE /v1/organisations/<organisation_id>
Organisation object
{
"id": "org-9RxFsXTgnWqwjK4apxBAn8",
"unique_id": "c105b862-f1ba-4197-9d97-57db63196b00",
"registered": "2017-06-01T14:37:12Z",
"name": "",
"company": null,
"billing_account": null,
"users": []
}
field | type | flags | description |
---|---|---|---|
id | string(uuid) | read-only | API unique identifier for the organisation |
unique_id | string | required | Unique identifier of the organisation on your platform |
registered | datetime | required | When the organisation registered on your platform |
name | string | optional | Organisation name |
company | string | optional | Hokodo unique identifier of the company |
billing_account | string(uuid) | read-only | API unique identifier for the billing account |
users | list | read-only | List of users attached to the organisation |
Note that registered
is the organisation's registration date on your platform, not with Hokodo.
Create an organisation
Request
POST /v1/organisations HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
{
"unique_id": "c105b862-f1ba-4197-9d97-57db63196b00",
"registered": "2017-06-01T14:37:12Z",
"name": "My organisation",
"company": "co-bqRyKAGaFrEEN8JMjWJiqk"
}
curl --request POST
--url https://api-sandbox.hokodo.co/v1/organisations \
--header "Authorization: Token <your_api_key>" \
--header "Content-Type: application/json" \
--data-binary "{
\"unique_id\": \"c105b862-f1ba-4197-9d97-57db63196b00\",
\"registered\": \"2017-06-01T14:37:12Z\",
\"name\": \"My organisation\",
\"company\": \"co-bqRyKAGaFrEEN8JMjWJiqk\"
}"
Responses
- organisation created successfully
201 Created
Content-Type: application/json
{
"id": "org-pHr6VCyzQJALUsePkatPBo",
"unique_id": "c105b862-f1ba-4197-9d97-57db63196b00",
"registered": "2017-06-01T14:37:12Z",
"name": "My organisation",
"company": "co-bqRyKAGaFrEEN8JMjWJiqk",
"users": []
}
- organisation already exists (identified by
unique_id
), it is updated
200 Ok
Content-Type: application/json
{
"id": "org-pHr6VCyzQJALUsePkatPBo",
"unique_id": "c105b862-f1ba-4197-9d97-57db63196b00",
"registered": "2017-06-01T14:37:12Z",
"name": "My organisation",
"company": "co-bqRyKAGaFrEEN8JMjWJiqk",
"users": []
}
To create an organisation, you create an Organisation
object.
Errors
errors | description |
---|---|
400 | a required field is missing or a field has incorrect format |
List organisations
Request
GET /v1/organisations HTTP/1.1
Authorization: Token <your_api_key>
curl --request GET
--url https://api-sandbox.hokodo.co/v1/organisations \
--header "Authorization: Token <your_api_key>"
Response
200 Ok
Content-Type: application/json
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": "org-pHr6VCyzQJALUsePkatPBo",
"unique_id": "c105b862-f1ba-4197-9d97-57db63196b00",
"registered": "2017-06-01T14:37:12Z",
"name": "My organisation",
"company": "co-bqRyKAGaFrEEN8JMjWJiqk",
"billing_account": "ba-5SvfKbhh8WsFdCp8p54eie",
"users": []
}
]
}
List organisations created by your platform
View organisation
Request
GET /v1/organisations/<organisation_id> HTTP/1.1
Authorization: Token <your_api_key>
curl --request GET
--url https://api-sandbox.hokodo.co/v1/organisations/org-pHr6VCyzQJALUsePkatPBo \
--header "Authorization: Token <your_api_key>"
Response
200 Ok
Content-Type: application/json
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": "org-pHr6VCyzQJALUsePkatPBo",
"unique_id": "c105b862-f1ba-4197-9d97-57db63196b00",
"registered": "2017-06-01T14:37:12Z",
"name": "My organisation",
"company": "co-bqRyKAGaFrEEN8JMjWJiqk",
"billing_account": "ba-5SvfKbhh8WsFdCp8p54eie",
"users": []
}
]
}
Retrieve an organisation created by your platform
Errors
errors | description |
---|---|
404 | the organisation_id is probably invalid, the organisation has not been found |
Modify organisation
Request
PATCH /v1/organisations/<organisation_id> HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
{
"unique_id": "c105b862-f1ba-4197-9d97-57db63196b01",
"registered": "2018-06-01T14:37:12Z",
"company": "co-bqRyKAGaFrEEN8JMjWJiqk"
}
curl --request PATCH
--url https://api-sandbox.hokodo.co/v1/organisations/org-pHr6VCyzQJALUsePkatPBo \
--header "Authorization: Token <your_api_key>" \
--header "Content-Type: application/json" \
--data-binary "{
\"unique_id\": \"c105b862-f1ba-4197-9d97-57db63196b01\",
\"registered\": \"2018-06-01T14:37:12Z"\,
\"company\": \"co-bqRyKAGaFrEEN8JMjWJiqk\"
}"
Response
200 Ok
Content-Type: application/json
{
"id": "org-pHr6VCyzQJALUsePkatPBo",
"unique_id": "c105b862-f1ba-4197-9d97-57db63196b01",
"registered": "2018-06-01T14:37:12Z",
"name": "My organisation",
"company": "co-bqRyKAGaFrEEN8JMjWJiqk",
"billing_account": "ba-5SvfKbhh8WsFdCp8p54eie",
"users": []
}
Modify an organisation created by your platform
Errors
errors | description |
---|---|
404 | the organisation_id is probably invalid, the organisation has not been found |
400 | a required field is missing or a field has incorrect format |
Delete an organisation
Request
DELETE /v1/organisations/<organisation_id> HTTP/1.1
Authorization: Token <your_api_key>
curl --request DELETE
--url https://api-sandbox.hokodo.co/v1/organisations/org-pHr6VCyzQJALUsePkatPBo \
--header "Authorization: Token <your_api_key>"
Responses
- regular response
204 No Content
- can not delete organisation, it has objects attached
409 Conflict
Content-Type: application/json
{
"detail": "Organisation has undeletable objects attached, it cannot be deleted."
}
Delete an organisation created by your platform. Please note, that you can not delete an organisation that has payment-related objects attached to it (such as deferred payments or offers, etc.)
Errors
errors | description |
---|---|
404 | the organisation_id is probably invalid, the organisation has not been found |
409 | an organisation can not be deleted because it has objects attached to it |
Manage users in organisation
Our API provides two alternative endpoint collections to manage relation between users and organisations. Below is the list of methods from the perspective of an organisation. For the list of methods from the perspective of a user, please refer to section Manage organisations of user
Organisation users endpoints
POST /v1/organisations/<organisation_id>/users
GET /v1/organisations/<organisation_id>/users
GET /v1/organisations/<organisation_id>/users/<user_id>
PATCH /v1/organisations/<organisation_id>/users/<user_id>
DELETE /v1/organisations/<organisation_id>/users/<user_id>
Organisation user object
{
"id": "user-mECT3e5n9i7gVGrbn2Pd38",
"email": "johnny@hokodo.co",
"role": "admin"
}
field | type | flags | description |
---|---|---|---|
id | string(uuid) | required | API unique identifier for the user |
string | read-only | Email of the user | |
role | role | required | Role of the user in the organisation |
User roles within organisations
Users can have one of the following roles in an organisation:
read-only
user can only see resources attached to the organisation (useful for an accountant for example).member
has the rights of a read-only user and can also get deferred payment.admin
has the rights of a member user and can also add members, remove members, or change role of members of the organisation.
Note: this list may be expanded in the future, please make sure your code doesn't break if a new role type is added.
Add user to organisation
Request
POST /v1/organisations/<organisation_id>/users HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
{
"id": "user-mECT3e5n9i7gVGrbn2Pd38",
"role": "admin"
}
curl --request POST
--url https://api-sandbox.hokodo.co/v1/organisations/org-pHr6VCyzQJALUsePkatPBo/users \
--header "Authorization: Token <your_api_key>" \
--header "Content-Type: application/json" \
--data-binary "{
\"id\": \"user-mECT3e5n9i7gVGrbn2Pd38\",
\"role\": \"admin"\
}"
Responses
- regular response
201 Created
Content-Type: application/json
{
"id": "user-mECT3e5n9i7gVGrbn2Pd38",
"email": "johnny@hokodo.co",
"role": "admin"
}
- user already added to the organisation
200 Ok
Content-Type: application/json
{
"id": "user-mECT3e5n9i7gVGrbn2Pd38",
"email": "johnny@hokodo.co",
"role": "admin"
}
- error (user not found and/or incorrect user role)
400 Bad Request
Content-Type: application/json
{
"id": [
"Invalid pk \"user-mECT3e5n9i7gVGrbn2Pd39\" - object does not exist."
],
"role": [
"\"reader\" is not a valid choice."
]
}
Attach previously created user to the organisation. When a user is already added to the organisation, but a different role is provided in the request, his existing role will be updated.
Users can have one of the following roles in an organisation:
To create a user, see the relevant section.
Errors
errors | description |
---|---|
400 | a required field is missing or a field has incorrect format |
View users of organisation
Request
GET /v1/organisations/<organisation_id>/users HTTP/1.1
Authorization: Token <your_api_key>
curl --request GET
--url https://api-sandbox.hokodo.co/v1/organisations/org-pHr6VCyzQJALUsePkatPBo/users \
--header "Authorization: Token <your_api_key>"
Response
200 Ok
Content-Type: application/json
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": "user-mECT3e5n9i7gVGrbn2Pd38",
"email": "johnny@hokodo.co",
"role": "admin"
}
]
}
List all current users of an organisation
View individual user of organisation
Request
GET /v1/organisations/<organisation_id>/users/<user_id> HTTP/1.1
Authorization: Token <your_api_key>
curl --request GET
--url https://api-sandbox.hokodo.co/v1/organisations/org-pHr6VCyzQJALUsePkatPBo/users/user-mECT3e5n9i7gVGrbn2Pd38 \
--header "Authorization: Token <your_api_key>"
Response
200 Ok
Content-Type: application/json
{
"id": "user-mECT3e5n9i7gVGrbn2Pd38",
"email": "johnny@hokodo.co",
"role": "admin"
}
Retrieve one specific user of an organisation
Errors
errors | description |
---|---|
404 | the user_id is probably invalid, the user has not been found |
Modify user role in organisation
Request
PATCH /v1/organisations/<organisation_id>/users/<user_id> HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
{
"role": "member"
}
curl --request POST
--url https://api-sandbox.hokodo.co/v1/organisations/org-pHr6VCyzQJALUsePkatPBo/users/user-mECT3e5n9i7gVGrbn2Pd38 \
--header "Authorization: Token <your_api_key>" \
--header "Content-Type: application/json" \
--data-binary "{
\"role\": \"member"\
}"
Responses
- regular response
200 Ok
Content-Type: application/json
{
"id": "user-mECT3e5n9i7gVGrbn2Pd38",
"email": "johnny@hokodo.co",
"role": "member"
}
- error (incorrect user role)
400 Bad Request
Content-Type: application/json
{
"role": [
"\"reader\" is not a valid choice."
]
}
Modify the role of a specific user in an organisation
Errors
errors | description |
---|---|
400 | the role field is missing or has incorrect value |
Remove user from organisation
Request
DELETE /v1/organisations/<organisation_id>/users/<user_id> HTTP/1.1
Authorization: Token <your_api_key>
curl --request DELETE
--url https://api-sandbox.hokodo.co/v1/organisations/org-pHr6VCyzQJALUsePkatPBo/users/user-mECT3e5n9i7gVGrbn2Pd38 \
--header "Authorization: Token <your_api_key>"
Response
204 No Content
Remove one specific user from the organisation
Errors
errors | description |
---|---|
404 | the user_id is probably invalid, the user has not been found |
Users
Users represent the individual customers on your platform. They are associated to one or multiple organisations, which themselves represent the company of these customers. A user can have different roles and permissions in each organisation.
Users not linked to an organisation cannot access orders, payment offers or deferred payments. Therefore, we suggest creating the organisation first, then create users linked to the organisation with the proper role.
User endpoints
POST /v1/users
GET /v1/users
GET /v1/users/<user_id>
PATCH /v1/users/<user_id>
DELETE /v1/users/<user_id>
User object
{
"id": "user-VG4i93EPLRamVFK6oXpvt9",
"email": "johnny@hokodo.co",
"unique_id": "",
"name": "John",
"phone": "",
"registered": "2017-06-01T14:37:12Z",
"organisations": [
{
"id": "org-FEjrdMsmhdNp34HxaZ6n63",
"role": "member"
}
]
}
field | type | flags | description |
---|---|---|---|
id | string(uuid) | read-only | API unique identifier for the user |
string | required | Email of the user | |
unique_id | string | optional | Unique identifier of the user on your platform (currently we don't validate its uniqueness and store it for your reference only) |
name | string | required | Full name of the user |
phone | string | optional | Phone number of the user |
registered | datetime | required | Date of user registration on your platform |
organisations | list | optional | List of organisations to which the user is linked (can be empty) |
organisations[*][id] | string(uuid) | required | API identifier of the organisation |
organisations[*][role] | role | required | Role of the user in the organisation |
Note that registered
is the user's registration date on your platform, not with Hokodo.
Create a user
Request
POST /v1/users HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
{
"name": "John",
"email": "johnny@hokodo.co",
"registered": "2017-06-01T14:37:12Z",
"organisations": [
{
"id": "org-FEjrdMsmhdNp34HxaZ6n63",
"role": "member"
}
]
}
curl --request POST \
--url https://api-sandbox.hokodo.co/v1/users \
--header "Authorization: Token <your_api_key>"
--header "Content-Type: application/json"
--data-binary="{
\"name\": \"John\",
\"email\": \"johnny@hokodo.co\",
\"registered\": \"2017-06-01T14:37:12Z\",
\"organisations\": [
{
\"id\": \"org-FEjrdMsmhdNp34HxaZ6n63\",
\"role\": \"member\"
}
]
}"
Response
- regular response
201 Created
Content-Type: application/json
{
"id": "user-VG4i93EPLRamVFK6oXpvt9",
"email": "johnny@hokodo.co",
"unique_id": "",
"name": "John",
"phone": "",
"registered": "2017-06-01T14:37:12Z",
"organisations": [
{
"id": "org-FEjrdMsmhdNp34HxaZ6n63",
"role": "member"
}
]
}
- error response
400 Bad Request
Content-Type: application/json
{
"email": [
"This field is required."
],
"name": [
"This field is required."
],
"registered": [
"This field is required."
]
}
To create a user, you create a User
object.
Note: Repeated POST
requests with user information that contains the same email address will trigger partial
updates on the existing user. Any organisations in this list will be appended to the list of organisations
the user is already a member of. If the list includes an organisation the user is currently a member of, but with a
different role, the user's role will be updated to the latest received.
errors | description |
---|---|
400 | a required field is missing |
List users
Request
GET /v1/users HTTP/1.1
Authorization: Token <your_api_key>
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/users \
--header "Authorization: Token <your_api_key>"
Response
200 OK
Content-Type: application/json
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": "user-mECT3e5n9i7gVGrbn2Pd38",
"email": "johnny@hokodo.co",
"unique_id": "",
"name": "John",
"phone": "",
"registered": "2017-06-01T14:37:12Z",
"organisations": [
{
"id": "org-FEjrdMsmhdNp34HxaZ6n63",
"role": "member"
}
]
}
]
}
List all users associated with your platform.
Get user
Request
GET /v1/users/<user_id> HTTP/1.1
Authorization: Token <your_api_key>
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/users/user-mECT3e5n9i7gVGrbn2Pd38 \
--header "Authorization: Token <your_api_key>"
Response
- regular response
200 OK
Content-Type: application/json
{
"id": "user-mECT3e5n9i7gVGrbn2Pd38",
"email": "johnny@hokodo.co",
"unique_id": "",
"name": "John",
"phone": "",
"registered": "2017-06-01T14:37:12Z",
"organisations": [
{
"id": "org-FEjrdMsmhdNp34HxaZ6n63",
"role": "member"
}
]
}
- user not found
404 Not Found
Content-Type: application/json
{
"detail": "Not found."
}
Look up a previously created user.
errors | description |
---|---|
404 | the user_id is probably invalid, the user has not been found |
Modify user
Request
PATCH /v1/users/<user_id> HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
{
"id": "user-mECT3e5n9i7gVGrbn2Pd38",
"unique_id": "some-unique-id",
"name": "Johnny",
"phone": "+1234567890",
"registered": "2018-06-01T14:37:10Z"
}
Response
200 OK
Content-Type: application/json
{
"id": "user-mECT3e5n9i7gVGrbn2Pd38",
"email": "johnny@hokodo.co",
"unique_id": "some-unique-id",
"name": "Johnny",
"phone": "+1234567890",
"registered": "2018-06-01T14:37:10Z",
"organisations": [
{
"id": "org-FEjrdMsmhdNp34HxaZ6n63",
"role": "member"
}
]
}
Update a previously created user.
User emails are read-only and cannot be modified through the API. To update a buyer email, please contact support@hokodo.co.
Please note that the organisations list appends to the user's existing organisations list. Supplying an existing
organisation in the list will update the user's role
on that organisation.
errors | description |
---|---|
404 | the user_id is probably invalid, the user has not been found |
400 | updating a user failed or some of the fields have incorrect format |
Delete user
Request
DELETE /v1/users/<user_id> HTTP/1.1
Authorization: Token <your_api_key>
curl --request DELETE \
--url https://api-sandbox.hokodo.co/v1/users/user-mECT3e5n9i7gVGrbn2Pd38 \
--header "Authorization: Token <your_api_key>"
Response
- regular response
204 No Content
- user not found
404 Not Found
Content-Type: application/json
{
"detail": "Not found."
}
Delete a previously created user.
Errors
errors | description |
---|---|
404 | the user_id is probably invalid, the user has not been found |
Manage organisations of user
You can manage users' memberships and roles in various organisations. Please refer to section Organisations regarding creating and managing organisations.
Our API provides two alternative endpoint collections to manage relations between users and organisations. Below is the list of methods from the perspective of a user. For the list of methods from the perspective of an organisation, please refer to section Manage users in organisation
User organisations endpoints
POST /v1/users/<user_id>/organisations
GET /v1/users/<user_id>/organisations
GET /v1/users/<user_id>/organisations/<organisation_id>
PATCH /v1/users/<user_id>/organisations/<organisation_id>
DELETE /v1/users/<user_id>/organisations/<organisation_id>
User organisation object
{
"id": "org-pHr6VCyzQJALUsePkatPBo",
"role": "admin"
}
field | type | flags | description |
---|---|---|---|
id | string(uuid) | required | API unique identifier for the organisation |
role | role | required | Role of the user in the organisation |
Add user to organisation
Request
POST /v1/users/<user_id>/organisations HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
{
"id": "org-pHr6VCyzQJALUsePkatPBo",
"role": "admin"
}
curl --request POST
--url https://api-sandbox.hokodo.co/v1/users/user-mECT3e5n9i7gVGrbn2Pd38/organisations \
--header "Authorization: Token <your_api_key>" \
--header "Content-Type: application/json" \
--data-binary "{
\"id\": \"org-pHr6VCyzQJALUsePkatPBo\",
\"role\": \"admin"\
}"
Responses
- regular response
201 Created
Content-Type: application/json
{
"id": "org-pHr6VCyzQJALUsePkatPBo",
"role": "admin"
}
- user already added to the organisation
200 Ok
Content-Type: application/json
{
"id": "org-pHr6VCyzQJALUsePkatPBo",
"role": "admin"
}
- error (organisation not found and/or incorrect user role)
400 Bad Request
Content-Type: application/json
{
"id": [
"Invalid pk \"org-mECT3e5n9i7gVGrbn2Pd39\" - object does not exist."
],
"role": [
"\"reader\" is not a valid choice."
]
}
Attach existing user to a previously created organisation. When a user is already added to the organisation, but a different role is provided in the request, his existing role will be updated.
To create a user, see the relevant section.
Errors
errors | description |
---|---|
400 | a required field is missing or a field has incorrect format |
View organisations of a user
Request
GET /v1/users/<user_id>/organisations HTTP/1.1
Authorization: Token <your_api_key>
curl --request GET
--url https://api-sandbox.hokodo.co/v1/users/user-mECT3e5n9i7gVGrbn2Pd38/organisations \
--header "Authorization: Token <your_api_key>"
Response
200 Ok
Content-Type: application/json
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": "org-pHr6VCyzQJALUsePkatPBo",
"role": "admin"
}
]
}
List all organisations of a user
View individual organisation of user
Request
GET /v1/users/<user_id>/organisations/<organisation_id> HTTP/1.1
Authorization: Token <your_api_key>
curl --request GET
--url https://api-sandbox.hokodo.co/v1/users/user-mECT3e5n9i7gVGrbn2Pd38/organisations/org-pHr6VCyzQJALUsePkatPBo \
--header "Authorization: Token <your_api_key>"
Response
200 Ok
Content-Type: application/json
{
"id": "org-pHr6VCyzQJALUsePkatPBo",
"role": "admin"
}
Retrieve one specific organisation of a user
Errors
errors | description |
---|---|
404 | the organisation_id is probably invalid, the organisation has not been found |
Modify user role in organisation
Request
PATCH /v1/users/<user_id>/organisations/<organisation_id> HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
{
"role": "member"
}
curl --request POST
--url https://api-sandbox.hokodo.co/v1/users/user-mECT3e5n9i7gVGrbn2Pd38/organisations/org-pHr6VCyzQJALUsePkatPBo \
--header "Authorization: Token <your_api_key>" \
--header "Content-Type: application/json" \
--data-binary "{
\"role\": \"member"\
}"
Responses
- regular response
200 Ok
Content-Type: application/json
{
"id": "org-pHr6VCyzQJALUsePkatPBo",
"role": "member"
}
- error (incorrect user role)
400 Bad Request
Content-Type: application/json
{
"role": [
"\"reader\" is not a valid choice."
]
}
Modify the role of the user in a specific organisation
Errors
errors | description |
---|---|
400 | the role field is missing or has incorrect value |
Remove user from organisation
Request
DELETE /v1/users/<user_id>/organisations/<organisation_id> HTTP/1.1
Authorization: Token <your_api_key>
curl --request DELETE
--url https://api-sandbox.hokodo.co/v1/users/user-mECT3e5n9i7gVGrbn2Pd38/organisations/org-pHr6VCyzQJALUsePkatPBo \
--header "Authorization: Token <your_api_key>"
Response
204 No Content
Remove the user from a specific organisation
Errors
errors | description |
---|---|
404 | the organisation_id is probably invalid, the organisation has not been found |
Credit Limits
Depending on the customer's company, the history of their orders and repayments, Hokodo can offer them deferred payments.
There are two situations where you might want to check whether one of your customers can obtain credit.
Your customer is at the checkout, and you want to check if that particular purchase is eligible for deferred payment. To do that, you use the Orders endpoint to inform Hokodo about the purchase, and the Payment Offers endpoint to check eligibility of the Order.
Your customer has not decided what they want to purchase, but you may wish to proactively inform them that they will be eligible for a Deferred Payment. For example, you could display a banner at the top of the page with their credit limit or perhaps add a credit limit section to their "My Account" page. The Credit Limits endpoint is designed for this second situation.
To find out your customer's credit limit, please use the following endpoint, with the associated customer Company in the URL.
POST /v1/payment/credit_limits/company/<company_id>
You will get a response containing the following information:
status
, either eligible or declined. This shows whether the customer can access credit terms. Arejection_reason
is given for rejected customers, which may relate to credit limits, or another factor such as being located in country not covered by Hokodo.- The customer's credit limit. This is the total credit available, including credit currently in use.
- The amount of credit currently in use by the customer.
- The amount of credit remaining to be used for future orders. You can use this to communicate a message such as "you have £XXX of Buy Now Pay Later credit available on our platform".
- The breakdown of the limit, usage, and remaining amount, into
hokodo_credit_limit
andmerchant_credit_limit
. This tells you how much credit is covered by Hokodo, vs. how much extra limit you have configured via Merchant Limits. - In the case of a rejection, actions that could be taken to affect the decision
Credit limits endpoint
POST /v1/payment/credit_limits/company/<company_id>
Credit limit object
{
"company": "co-74cgmhG9U79oTWGEW4jeDW",
"status": "eligible",
"rejection_reason": null,
"credit_limit": {
"currency": "GBP",
"amount_available": 987654,
"amount_in_use": 123456,
"amount": 1111110
},
"hokodo_credit_limit": {
"currency": "GBP",
"amount_available": 507654,
"amount_in_use": 103456,
"amount": 611110
},
"merchant_credit_limit": {
"currency": "GBP",
"amount_available": 480000,
"amount_in_use": 20000,
"amount": 500000
},
"credit_actions": [
{
"code": "company-financials",
"description": "Please submit {months} bank statements",
"params": {"months": 4},
"description_display": "Please submit 4 months of bank statements"
}
]
}
field | type | description |
---|---|---|
company | string(uuid) | API unique identifier for the company |
status | string | Current credit approval status (eligible or declined ) |
rejection_reason | dictionary | If status is declined , details about why, otherwise null |
credit_limit | dictionary | Current credit limit, including the protected and unprotected portions |
credit_limit[currency] | currency (ISO 4217 code) | Currency of the stated limit (e.g. GBP , EUR ) |
credit_limit[amount_available] | int | Amount currently available, in minor units (cents/pence) |
credit_limit[amount_in_use] | int | Amount currently in use, in minor units (cents/pence) |
credit_limit[amount] | int | Total amount, in minor units (cents/pence) |
hokodo_credit_limit | dictionary | Current limit of credit fully covered by Hokodo, if approved |
hokodo_credit_limit[amount_available] | int | Amount currently available, in minor units (cents/pence) |
hokodo_credit_limit[amount_in_use] | int | Amount currently in use, in minor units (cents/pence) |
hokodo_credit_limit[amount] | int | Total amount, in minor units (cents/pence) |
merchant_credit_limit | dictionary | Current Merchant Limit and exposure |
merchant_credit_limit[amount_available] | int | Amount currently available, in minor units (cents/pence) |
merchant_credit_limit[amount_in_use] | int | Amount currently in use, in minor units (cents/pence) |
merchant_credit_limit[amount] | int | Total amount, in minor units (cents/pence) |
credit_actions | list | Possible actions that can affect the decision positively |
credit_actions[code] | string | A text label identifying the action |
credit_actions[description_display] | string | description with params substituted in |
credit_actions[description] | string | A detailed explanation of the action a buyer should take when submitting a credit limit request |
credit_actions[params] | dictionary | Pairs of values that should be substituted in to description |
Request company credit limit
Requests
POST /v1/payment/credit_limits/company/co-74cgmhG9U79oTWGEW4jeDW/ HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
{
"currency": "GBP",
"metadata": {
"subscriber": true,
"buyer_id": 2,
"checkouts_count": 42,
"checkouts_value": 8000.42,
}
}
curl --request POST \
--url https://api-sandbox.hokodo.co/v1/payment/credit_limits/company/co-74cgmhG9U79oTWGEW4jeDW/ \
--header "Authorization: Token <your_api_key>" \
--header "Content-Type: application/json" \
--data-binary '{
"currency": "GBP",
"metadata": { "buyer_id": 2 }
}'
Responses
- eligible
200 OK
Content-Type: application/json
{
"company": "co-74cgmhG9U79oTWGEW4jeDW",
"status": "eligible",
"rejection_reason": null,
"credit_limit": {
"currency": "GBP",
"amount_available": 987654,
"amount_in_use": 123456,
"amount": 1111110
},
"hokodo_credit_limit": {
"currency": "GBP",
"amount_available": 507654,
"amount_in_use": 103456,
"amount": 611110
},
"merchant_credit_limit": {
"currency": "GBP",
"amount_available": 480000,
"amount_in_use": 20000,
"amount": 500000
},
"credit_actions": []
}
- declined
200 OK
Content-Type: application/json
{
"company": "co-74cgmhG9U79oTWGEW4jeDW",
"status": "declined",
"rejection_reason": {
"code": "buyer-country",
"detail": "We're currently unable to provide payment plans to Buyers domiciled in {debtor_country}.",
"params": {
"debtor_country": "Ireland"
}
},
"credit_limit": {
"currency": "GBP",
"amount_available": 0,
"amount_in_use": 123456,
"amount": 0
},
"hokodo_credit_limit": {
"currency": "GBP",
"amount_available": null,
"amount_in_use": 123456,
"amount": null
},
"merchant_credit_limit": {
"currency": "GBP",
"amount_available": 0,
"amount_in_use": 0,
"amount": 0
},
"credit_actions": [
{
"code": "company-financials",
"description": "Please submit {months} bank statements",
"params": {"months": 4},
"description_display": "Please submit 4 months of bank statements"
}
]
}
The currency is optional in the request, and defaults to EUR
if not provided.
It is advisable to request the credit limit in the currency used by the company in question. For example,
use "currency": "GBP"
when requesting the credit limit of a UK company.
metadata
is also optional, but supplying historical buyer data can help Hokodo make more accurate risk decisions
and reduce friction for your buyers at checkout.
The field should be submitted as a set of key-value pairs. Recommended fields are detailed below.
field | type | description |
---|---|---|
currency | currency (ISO 4217 code) | Currency to view the currency in (e.g. GBP , EUR ) |
metadata | dictionary | Set of key-value pairs you can attach to the object. |
metadata[*][subscriber] | boolean | Whether the buyer pays a monthly fee, eg. for any extra services |
metadata[*][buyer_id] | string | The unique identifier of the buyer on your platform |
metadata[*][channel] | string | The channel the buyer was acquired via (e.g. search engine, social media, referral, etc.) |
metadata[*][checkouts_count] | int | The number of checkouts completed by the buyer to date, excluding Hokodo orders |
metadata[*][checkouts_value] | int | The value of checkouts completed by the buyer to date, excluding Hokodo orders |
Errors
errors | description |
---|---|
400 | A field is not in the expected format |
Some tips regarding the credit_limit
endpoint
- Hokodo-protected credit declined, but eligible for Merchant Limit
200 OK
Content-Type: application/json
{
"company": "co-74cgmhG9U79oTWGEW4jeDW",
"status": "eligible",
"rejection_reason": {
"code": "buyer-limit",
"detail": "This invoice would exceed the limit of the value of invoices that Hokodo can insure for this company as a Buyer.",
"params": {}
},
"credit_limit": {
"currency": "GBP",
"amount_available": 480000,
"amount_in_use": 143456,
"amount": 500000
},
"hokodo_credit_limit": {
"currency": "GBP",
"amount_available": null,
"amount_in_use": 123456,
"amount": null
},
"merchant_credit_limit": {
"currency": "GBP",
"amount_available": 480000,
"amount_in_use": 20000,
"amount": 500000
},
"credit_actions": []
}
Please note that in general the amount
will equal amount_available
plus amount_in_use
.
Occasionally this will not be the case. There are two reasons this might happen:
- If the customer has other exposures with Hokodo (on other platforms) that have eroded some of their limit on your platform. In general we avoid this scenario by ring-fencing limits for platforms, but occasionally this is not possible (e.g. for customers with very small limits).
- If you are using Merchant Limits and the buyer is not eligible for a
hokodo_credit_limit
, but still has somemerchant_credit_limit
left. In this case, theamount_in_use
may include some Hokodo-protected amount owed from before, whereasamount
andamount_available
refer to the amounts available now, i.e. the Merchant Limit in this case.
"status" vs. "rejection_reason": which to check
The "status"
field represents whether the buyer is eligible for payment terms with Hokodo-protected credit and/or a Merchant Limit.
In the case that a buyer is declined for Hokodo-protected credit, but eligible under a Merchant Limit, they will have "status": "eligible"
, but a non-null rejection_reason
.
This shows that they can get payment terms, but also allows you to see why they are rejected for Hokodo-protected credit.
Credit Limits (Legacy)
Depending on the customer's company, the history of their orders and repayments, Hokodo can offer them deferred payments.
There are two situations where you might want to check whether one of your customers can obtain credit.
Your customer is at the checkout, and you want to check if that particular purchase is eligible for deferred payment. To do that, you use the Orders endpoint to inform Hokodo about the purchase, and the Payment Offers endpoint to check eligibility of the Order.
Your customer has not decided what they want to purchase, but you may wish to proactively inform them that they will be eligible for Deferred Payment. For example, you could display a banner at the top of the page with their credit limit or perhaps add a credit limit section to their "My Account" page. The CreditLimit endpoint is designed for this second situation.
To find out your customer's credit limit, please use the following endpoint, with the associated customer Company in the URL.
GET /v1/payment/credit_limits/company/<company_id>
You will get one of the two possible responses:
Rejected: no limit available
Accepted: the response will contain several blocks, such as:
- the available amount at this point in time for the given company: this is the maximum credit we are able to extend at this point in time, considering the credit already in use by this user, their maximum credit limit, our underwriting rules, etc.
- the amount of the company’s credit limit currently in use with Hokodo for this company in relation to the platform (this might be useful to show messages like "you are using £XXX out of your £YYYY credit limit at our marketplace"),
- history of past credit limits requested by your platform (as a reference, to help your customer support and operations department know the history of credit limit increases/decreases).
CreditLimit endpoints
GET /v1/payment/credit_limits/company/<company_id>
CreditLimit object
{
"company": "co-74cgmhG9U79oTWGEW4jeDW",
"status": "eligible",
"current_credit_limit": {
"currency": "GBP",
"amount": 200000,
"amount_in_use": 99700,
"amount_available": 100300
},
"credit_limit_history": [
{
"valid_from": "2020-07-16T08:44:49.059Z",
"valid_to": null,
"currency": "GBP",
"amount": 200000
},
{
"valid_from": "2020-06-02T09:12:34.059Z",
"valid_to": "2020-07-16T08:44:49.059Z",
"currency": "GBP",
"amount": 150000
},
{
"valid_from": "2020-05-18T18:18:18.059Z",
"valid_to": "2020-06-02T09:12:34.059Z",
"currency": "GBP",
"amount": 100000
}
],
"credit_actions": [
{
"code": "company-financials",
"description": "Please submit {months} bank statements",
"params": {"months": 4},
"description_display": "Please submit 4 months of bank statements"
}
]
}
field | type | flags | description |
---|---|---|---|
company | string(uuid) | required | API unique identifier of the associated company |
status | string | read-only | Current credit approval status (eligible or declined ) |
current_credit_limit | dictionary | read-only | Current credit limit if approved |
current_credit_limit[currency] | string (ISO 4217 code) | read-only | Currency of the stated limit (e.g. GBP , EUR ) |
current_credit_limit[amount] | int | read-only | Total credit limit available, in cents |
current_credit_limit[amount_in_use] | int | read-only | Credit limit currently in use by deferred payments, in cents |
current_credit_limit[amount_available] | int | read-only | Credit limit currently available, in cents |
credit_limit_history | list | read-only | Current credit limit if approved |
credit_limit_history[*][currency] | string (ISO 4217 code) | read-only | Currency of the stated limit (e.g. GBP , EUR ) |
credit_limit_history[*][amount] | int | read-only | Total credit limit available, in cents |
credit_limit_history[*][valid_from] | datetime | read-only | From when the historical credit limit was valid |
credit_limit_history[*][valid_to] | datetime | read-only | Until when the historical credit limit was valid |
credit_actions | list | Possible actions that can affect the decision positively | |
credit_actions[code] | string | A text label identifying the action | |
credit_actions[description_display] | string | description with params substituted in |
|
credit_actions[description] | string | A detailed explanation of the action a buyer should take when submitting a credit limit request | |
credit_actions[params] | dictionary | Pairs of values that should be substituted in to description |
Request a new Credit approval and limit
Request
GET /v1/payment/credit_limits/company/{company_id} HTTP/1.1
Content-Type: application/json
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/payment/credit_limits/company/{company_id} \
--header "Content-Type: application/json"
Responses
- Customer rejected
200 OK
Content-Type: application/json
{
"company": "co-74cgmhG9U79oTWGEW4jeDW",
"status": "declined",
"current_credit_limit": null,
"credit_limit_history": []
}
- Customer accepted
200 OK
Content-Type: application/json
{
"company": "co-74cgmhG9U79oTWGEW4jeDW",
"status": "eligible",
"current_credit_limit": {
"currency": "GBP",
"amount": 200000,
"amount_in_use": 99700,
"amount_available": 100300
},
"credit_limit_history": [
{
"valid_from": "2020-07-16T08:44:49.059Z",
"valid_to": null,
"currency": "GBP",
"amount": 200000
},
{
"valid_from": "2020-06-02T09:12:34.059Z",
"valid_to": "2020-07-16T08:44:49.059Z",
"currency": "GBP",
"amount": 150000
},
{
"valid_from": "2020-05-18T18:18:18.059Z",
"valid_to": "2020-06-02T09:12:34.059Z",
"currency": "GBP",
"amount": 100000
}
],
"credit_actions": []
}
This endpoint is used to query credit approval and credit limits for your customer. The only required field is company
, in the URL.
It returns:
- the status of the credit approval, eligible or declined,
- the amount of the credit limit if approved, as well as the amount currently in use and the amount still available,
- the history of previous credit limits for this customer, if available.
field | type | flags | description |
---|---|---|---|
company | string(uuid) | required | API unique identifier of the customer company queried |
Merchant Limits
Hokodo allows you to top-up your buyer's credit limit at your own risk. You do this by setting limits for specific buyers, called Merchant Limits. These are your limits for the buyers.
Merchant Limits apply on top of the Hokodo credit limit. A buyer with a Hokodo credit limit of €400 and a Merchant Limit of €200 can borrow €600 in total.
Funds lent using Merchant Limits are still financed by Hokodo, and we still attempt to recover non-payment from the buyer using our collections process. Any non-payment that cannot be recovered is subtracted from your Payouts.
There are two kinds of Merchant Limits:
- Per-buyer Merchant Limits
- The Default Merchant Limit that applies to any buyers without a per-buyer limit. It is the default limit for each buyer, not a total aggregate limit for all buyers.
The limit applied to a particular buyer is determined in the following order of precedence:
- The per-buyer limit for this buyer, if one exists.
- The default limit, if one exists.
- If neither is set, the limit is 0.
Merchant Limit object
{
"currency": "GBP",
"limits": {
"GBP": 200000,
"EUR": 227946,
"USD": 263710
},
"is_active": true
}
field | type | description |
---|---|---|
currency | string | Currency the limit was set in (ISO 4217 code) |
limits | dictionary | Total limits, provided in various currencies |
limits["GBP"] | int | Total limit expressed in GBP, in minor units (pence) |
limits["EUR"] | int | Total limit expressed in EUR, in minor units (cents) |
limits["USD"] | int | Total limit expressed in USD, in minor units (cents) |
is_active | boolean | If false , this limit does not apply |
Limits are set in one particular currency, determined by the currency
field. The entries in limits
are converted
from that currency using Hokodo's exchange rates, to allow you to know the exact limit applied in each currency.
Per-buyer endpoints
GET /v1/payment/merchant_limits/company/<company_id>
PUT /v1/payment/merchant_limits/company/<company_id>
PATCH /v1/payment/merchant_limits/company/<company_id>
DELETE /v1/payment/merchant_limits/company/<company_id>
Default limits endpoints
Default Merchant Limits are set and retrieved separately from the per-buyer limits.
GET /v1/payment/merchant_limits/default
PUT /v1/payment/merchant_limits/default
PATCH /v1/payment/merchant_limits/default
DELETE /v1/payment/merchant_limits/default
Get merchant limit
If no Merchant Limit has been set, this endpoint returns an HTTP 404
status code.
Errors
errors | description |
---|---|
404 | No per-buyer limit exists for this company_id |
Requests
GET /v1/payment/merchant_limits/company/<company_id>/ HTTP/1.1
Authorization: Token <your_api_key>
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/payment/merchant_limits/company/co-74cpmhG9U79aTWGEW4je2W/ \
--header "Authorization: Token <your_api_key>"
Responses
200 OK
Content-Type: application/json
{
"currency": "GBP",
"limits": {
"GBP": 200000,
"EUR": 227946,
"USD": 263710
},
"is_active": true
}
Create or Update a merchant limit
In order to set a Merchant Limit, make a PUT
request containing the currency
, limit
and is_active
.
There is one Merchant Limit covering all currencies. It is set in a particular currency, and conversions are applied
when comparing it to orders in other currencies. The currency
field sets which currency the limit is specified in.
The conversion is calculated using a fixed exchange rate €1 = £0.8774 = $1.1569.
For example, if you set "limit": 200000, "currency": "EUR"
, and the buyer makes orders of €1000 and £800,
most of that buyer's limit is now used up.
The special string "infinity"
sets an infinite limit.
field | type | description |
---|---|---|
currency | string | Currency the limit is set in (ISO 4217 code) |
limit | int | Total limit in minor units, specified in currency . The special string "infinity" sets an infinite limit. |
is_active | boolean | If false , this limit does not apply |
Errors
errors | description |
---|---|
400 | A field is not in the expected format |
Requests
PUT /v1/payment/merchant_limits/company/<company_id>/ HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
{
"currency": "EUR",
"is_active": true,
"limit": 1000
}
curl --request PUT \
--url https://api-sandbox.hokodo.co/v1/payment/merchant_limits/company/co-74cpmhG9U79aTWGEW4je2W/ \
--header "Authorization: Token <your_api_key>" \
--header "Content-Type: application/json" \
--data-binary '{
"currency": "EUR",
"is_active": true,
"limit": 1000
}'
Responses
200 OK
Content-Type: application/json
{
"currency": "EUR",
"limits": {
"GBP": 877,
"EUR": 1000,
"USD": 1156
},
"is_active": true
}
Delete a merchant limit
In order to delete a merchant limit, make a DELETE
request to the per-buyer or default limit endpoint.
Deleting a limit has the same effect as setting "is_active": false
, but the record of the limit will also be removed.
Subsequent GET
requests to this endpoint will return an HTTP 404
status code.
DELETE /v1/payment/merchant_limits/company/<company_id>/ HTTP/1.1
Authorization: Token <your_api_key>
curl --request DELETE \
--url https://api-sandbox.hokodo.co/v1/payment/merchant_limits/company/co-74cpmhG9U79aTWGEW4je2W/ \
--header "Authorization: Token <your_api_key>"
Responses
200 OK
Content-Type: application/json
{
"currency": "EUR",
"limits": {
"GBP": 877,
"EUR": 1000,
"USD": 1156
},
"is_active": true
}
Billing Accounts
If the order frequency is above 5 or 10 transactions per buyer per month, we would recommend Billing Accounts for your Buyers. Billing Accounts govern the generation of Statements of Account. Statements of account list all the Captures and Refunds from a given period.
This encourages buyers to pay Statements rather than the individual invoices. That way, buyers only need to reconcile one bank statement line item with the Hokodo Statement for the month’s business, rather than reconcile many bank line items with many invoices. We also provide a .csv file along with the statement files so that buyers can reconcile the Statement contents with their own systems.
Billing account endpoints
POST /v1/payment/billing_accounts
GET /v1/payment/billing_accounts
GET /v1/payment/billing_accounts/<billing_account_id>
PATCH /v1/payment/billing_accounts/<billing_account_id>
There are also endpoints to get the Billing Accounts for a particular Company or Organisation:
GET /v1/companies/<company_id>/billing_accounts
GET /v1/organisations/<organisation_id>/billing_accounts
Billing Account object
{
"id": "ba-5SvfKbhh8WsFdCp8p54eie",
"active": true,
"default": true,
"created": "2023-08-30T16:29:06.852559Z",
"modified": "2023-08-30T16:29:06.852619Z",
"deactivated": null,
"organisations": [
"org-cPJRZJJiQ7prk4yHYQY6TK"
],
"emails": {
"to": [
"invoices@restaurant.com"
],
"cc": [
"secondary@restaurant.com"
]
},
"payment_terms": {
"period": "1m",
"due_date_offset": 20
}
}
field | type | flags | description |
---|---|---|---|
id | string(uuid) | read-only | API unique identifier for the billing account |
active | boolean | If the billing account is active | |
default | boolean | optional | Default billing account for organisations created for the company |
created | datetime | read-only | Creation date |
modified | datetime | read-only | Modification date |
deactivated | datetime | read-only | Deactivation date |
organisations | list[string(uuid)] | required | The list of organisations linked to the billing account |
emails | dictionary | required | Email addresses that will be sent the statements |
emails[to] | list[string] | required but can be empty | Emails "to" |
emails[cc] | list[string] | required but can be empty | Emails "cc" |
payment_terms | dictionary | required | Payment Terms |
payment_terms[period] | string | required | Payment Terms |
payment_terms[due_date_offset] | int | required | Payment Terms |
payment_terms[offset_type] | int | optional | Payment Terms |
Payment terms
This refers to the billing period. The exact details of the payment terms are specific to each merchant and configured by your Solutions Engineer during onboarding. These details are:
- the day the statement
period
(month/fortnight/week) start on - the number of days between the end of the statement
period
, and its payment due date (known asdue_date_offset
) - the
offset_type
specifies whether thedue_date_offset
is in days or months after the end of the statement. The defaultoffset_type
is "days".
Possible values of period
are:
1m
: Monthly14d
: Fortnightly7d
: Weekly
and other options that can be configured by your solutions engineer.
The value of due_date_offset
is a positive int
and must match a pre-set ["period", "due_date_offset", "offset_type"]
combination on
your account. Please contact your solutions engineer if in doubt about the available options
Default billing accounts
A Billing Account can be set as the default
for all new organisations created for the company. Any new organisation
created on your platform for the organisations company will be added to the default
billing account.
Create a billing account
Request
POST /v1/payment/billing_accounts HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
{
"organisations": ["org-idcPJRZJJiQ7prk4yHYQY6TK"],
"emails": {
"to": ["invoices@restaurant.com"],
"cc": ["secondary@restaurant.com"]
},
"default": true,
"payment_terms": {
"period": "1m",
"due_date_offset": 20
}
}
curl --request POST \
--url https://api-sandbox.hokodo.co/v1/payment/billing_accounts \
--header "Content-Type: application/json" \
--header "Authorization: <your_api_key>" \
--data-binary '{
"organisations": ["org-idcPJRZJJiQ7prk4yHYQY6TK"],
"emails": {
"to": ["invoices@restaurant.com"],
"cc": ["secondary@restaurant.com"]
},
"default": true,
"payment_terms": {
"period": "1m",
"due_date_offset": 20
}
}'
Responses
- success response
201 Created
Content-Type: application/json
{
"id": "ba-5SvfKbhh8WsFdCp8p54eie",
"active": true,
"default": true,
"created": "2023-08-30T16:29:06.852559Z",
"modified": "2023-08-30T16:29:06.852619Z",
"deactivated": null,
"organisations": [
"org-idcPJRZJJiQ7prk4yHYQY6TK"
],
"emails": {
"to": [
"invoices@restaurant.com"
],
"cc": [
"secondary@restaurant.com"
]
},
"payment_terms": {
"period": "1m",
"due_date_offset": 20,
"offset_type": "days"
}
}
- error response (example)
400 Bad Request
Content-Type: application/json
{
"organisations": [
"Invalid pk \"org-Gy4sQUpNddgyLAma3h8WQ3\" - object does not exist."
],
"to": {
"0": [
"Enter a valid email address."
]
},
"payment_terms": [
"You don't have billing account terms set up for period '7d' and offset '60'"
],
"default": [
"There is already a default billing account for this platform and company."
]
}
Errors
errors | description |
---|---|
400 | A required field is missing or some of the fields have incorrect values |
List billing accounts
Request
GET /v1/payment/billing_accounts HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/payment/billing_accounts \
--header "Content-Type: application/json" \
--header "Authorization: <your_api_key>"
Response
200 Ok
Content-Type: application/json
{
"count": 3,
"next": null,
"previous": null,
"results": [
{
"id": "ba-5SvfKbhh8WsFdCp8p54eie",
"active": true,
"default": true,
"created": "2023-08-30T16:29:06.852559Z",
"modified": "2023-08-30T16:29:06.852619Z",
"deactivated": null,
"organisations": [
"org-idcPJRZJJiQ7prk4yHYQY6TK", "org-Gy4sQUpNddgyLAma3h8WQ3"
],
"emails": {
"to": [
"Happy@southrestaurant.com"
],
"cc": []
},
"payment_terms": {
"period": "7d",
"due_date_offset": 3,
"offset_type": "days"
}
},
{
"id": "ba-hofiCfoZN64KJQoq8kDfRf",
"active": false,
"default": false,
"created": "2023-06-30T16:29:06.852559Z",
"modified": "2023-06-30T16:29:06.852619Z",
"deactivated": null,
"organisations": [
"org-idcPJRZJJiQ7prk4yHYQY6TK", "org-Gy4sQUpNddgyLAma3h8WQ3"
],
"emails": {
"to": [
"Happy@southrestaurant.com"
],
"cc": []
},
"payment_terms": {
"period": "1m",
"due_date_offset": 20,
"offset_type": "days"
}
},
{
"id": "ba-qeDkPMCYufuXpH6qA2qvqh",
"active": true,
"default": false,
"created": "2023-05-30T16:25:43.335278Z",
"modified": "2023-05-30T16:25:43.335340Z",
"deactivated": null,
"organisations": [
"org-idcPJRZJJiQ7prk4yHYQY6TK"
],
"emails": {
"to": [
"giselle@westrestaurant.com"
],
"cc": [
"denis@westrestaurant.com"
]
},
"payment_terms": {
"period": "1m",
"due_date_offset": 19,
"offset_type": "days"
}
}
]
}
List billing accounts created by your platform.
List for a particular company or organisation
These endpoints will list only the billing accounts for the given company or organisation:
GET /v1/companies/<company_id>/billing_accounts
GET /v1/organisations/<organisation_id>/billing_accounts
Filters and ordering
You can order by:
- Created date
GET /v1/payment/billing_accounts?ordering=created
- Deactivated date
GET /v1/payment/billing_accounts?ordering=deactivated
- Active/not active
GET /v1/payment/billing_accounts?ordering=active
You can filter on:
- Active:
true
|false
GET /v1/payment/billing_accounts?active=true
And combine both:
GET /v1/payment/billing_accounts?ordering=deactivated&active=false
View billing account
Requests
- request one billing account
GET /v1/payment/billing_accounts/<billing_account_id> HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/payment/billing_accounts/<billing_account_id> \
--header "Authorization: <your_api_key>"
Responses
- Success response with optional expansion
200 Ok
Content-Type: application/json
{
"id": "ba-G4Xm4PHferPqdQhi8AQgW5",
"active": false,
"default": true,
"created": "2023-08-25T13:18:50.268382Z",
"modified": "2023-08-30T09:32:34.380213Z",
"deactivated": "2023-08-30T09:32:34.380090Z",
"organisations": [
"org-EzhfgufFRozsLMBMKqkcaQ"
],
"emails": {
"to": [
"a_mail@restaurant.com",
"another_mail@restaurant.com"
],
"cc": []
},
"payment_terms": {
"period": "1m",
"due_date_offset": 20,
"offset_type": "days"
}
}
- billing account not found
404 Not Found
Content-Type: application/json
{
"detail": "Not found."
}
Errors
errors | description |
---|---|
404 | The billing_account_id is probably invalid, the billing account has not been found |
Modify billing account
Change emails
If you change the emails
, the whole dictionary of emails will be replaced with the dictionary you provide (to
and cc
)
Request Example: Update emails
PATCH /v1/payment/billing_accounts/<billing_account_id> HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
{
"emails": {
"to": ["a_mail@restaurant.com", "another_mail@restaurant.com"],
"cc": []
}
}
curl --request PATCH \
--url https://api-sandbox.hokodo.co/v1/payment/billing_accounts/<billing_account_id> \
--header "Content-Type: application/json" \
--header "Authorization: <your_api_key>" \
--data-binary '{
"emails": {
"to": ["a_mail@restaurant.com", "another_mail@restaurant.com"],
"cc": []
}
}'
Response
200 Ok
Content-Type: application/json
{
"id": "ba-G4Xm4PHferPqdQhi8AQgW5",
"active": true,
"default": false,
"created": "2023-08-25T13:18:50.268382Z",
"modified": "2023-08-25T13:20:20.465257Z",
"deactivated": null,
"organisations": [
"org-EzhfgufFRozsLMBMKqkcaQ"
],
"emails": {
"to": [
"a_mail@restaurant.com",
"another_mail@restaurant.com"
],
"cc": []
},
"payment_terms": {
"period": "1m",
"due_date_offset": 20,
"offset_type": "days"
}
}
Errors
errors | description |
---|---|
400 | A required field is missing or some of the fields have incorrect values |
409 | The billing account has been deactivated and cannot be updated |
Deactivate a billing account
You can deactivate a billing account.
Deactivated billing accounts do not generate new Statements. The existing open statement will be closed on its end_date
as usual, and its statement emails will be sent out.
Deactivated billing accounts cannot be re-activated.
Request deactivate billing account
PATCH /v1/payment/billing_accounts/<billing_account_id> HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
{
"active": false
}
curl --request PATCH \
--url https://api-sandbox.hokodo.co/v1/payment/billing_accounts/<billing_account_id> \
--header "Content-Type: application/json" \
--header "Authorization: <your_api_key>" \
--data-binary '{
"active": false
}'
Response
200 Ok
Content-Type: application/json
{
"id": "ba-XepNnfJe3QQ4wXCfYY4Uq3",
"active": false,
"default": false,
"created": "2023-09-01T14:00:25.744124Z",
"modified": "2023-09-01T14:09:52.101054Z",
"deactivated": "2023-09-01T14:09:52.100968Z",
"organisations": [
"org-jqCceJQ9QeiH8n3H4Fakk7"
],
"emails": {
"to": [
"invoices@restaurant.com"
],
"cc": [
"secondary@restaurant.com"
]
},
"payment_terms": {
"period": "1m",
"due_date_offset": 20,
"offset_type": "days"
}
}
Errors
errors | description |
---|---|
400 | A required field is missing or some of the fields have incorrect values |
409 | The billing account has already been deactivated |
Modify a deactivated billing account
Once a billing account has been deactivated, it is read-only. It cannot re-activated nor modified.
409 Conflict
Content-Type: application/json
{
"detail": "Billing account cannot be updated because it has been deactivated (2023-09-01 14:09:52.100968+00:00)"
}
Statements
Statements show the transaction history over a statement period. Statements list all the Captures, Refunds and Payments that took place in that period. The Buyer is encouraged to pay the statement balance on the due date, as one payment. The statement is emailed to the address specified in the Billing Account at the end of the statement period.
Statement endpoints
GET /v1/payment/billing_accounts/<billing_account_id>/statements
GET /v1/payment/billing_accounts/<billing_account_id>/statements/<statement_id>
GET /v1/payment/billing_accounts/<billing_account_id>/statements/<statement_id>/documents
GET /v1/payment/billing_accounts/<billing_account_id>/statements/<statement_id>/documents/<document_id>
Statement object
{
"id": "st-Lt2q4F3jMhKCNpGAt9fhXM",
"public_id": "S-PGK2-DY55",
"start_date": "2023-09-01",
"end_date": "2023-09-30",
"due_date": "2023-10-20",
"status": "open",
"events_total": 13824,
"captures_total": 13824,
"refunds_total": 0,
"payments_total": 0,
"opening_balance": 0,
"closing_balance": null,
"events": [
{
"id": "dpevnt-B9tuFhWdTLjQ5NVDFCKY45",
"deferred_payment_id": "defpay-jprM4x5862uZu66gxuLNTe",
"organisation_id": "org-kFNAdsxqp8ChB2G5YSj9Cg",
"organisation_name": "Buyer Ltd",
"metadata": {
"note": "Capturing 1000 worth of bonbons",
"supplier_id": "3",
"supplier_ref": "33",
"supplier_name": "A supplier that is ok",
"credit_note_ref": "3"
},
"created": "2023-09-08T13:35:36.410178Z",
"type": "capture",
"amount": 1000
},
{
"id": "dpevnt-zXiv6QeLUcJZSH3T9aYrHL",
"deferred_payment_id": "defpay-jprM4x5862uZu66gxuLNTe",
"organisation_id": "org-kFNAdsxqp8ChB2G5YSj9Cg",
"organisation_name": "Buyer Ltd",
"metadata": {
"note": "Capturing full amount",
"supplier_id": "4",
"supplier_ref": "44",
"supplier_name": "Another supplier",
"credit_note_ref": "4"
},
"created": "2023-09-08T13:35:56.070128Z",
"type": "capture",
"amount": 5912
},
{
"id": "dpevnt-mWpCTkY69vPDkcUtWTYhba",
"deferred_payment_id": "defpay-2RzbCEGoerAqLhBT8cCdyX",
"organisation_id": "org-kFNAdsxqp8ChB2G5YSj9Cg",
"organisation_name": "Buyer Ltd",
"metadata": {
"note": "Capturing 1000 worth of bonbons",
"supplier_id": "1",
"supplier_ref": "11",
"supplier_name": "A great supplier",
"credit_note_ref": "1"
},
"created": "2023-09-12T14:38:14.991165Z",
"type": "capture",
"amount": 1000
},
{
"id": "dpevnt-ritfGaqfXaLJYGSbq8VHTd",
"deferred_payment_id": "defpay-2RzbCEGoerAqLhBT8cCdyX",
"organisation_id": "org-kFNAdsxqp8ChB2G5YSj9Cg",
"organisation_name": "Buyer Ltd",
"metadata": {
"note": "Capturing full amount",
"supplier_id": "4",
"supplier_ref": "44",
"supplier_name": "Another supplier",
"credit_note_ref": "4"
},
"created": "2023-09-12T14:38:27.196703Z",
"type": "capture",
"amount": 5912
}
]
}
field | type | description |
---|---|---|
id | string(uuid) | API unique identifier for the statement |
public_id | string | Public id of the statement |
start_date | date | Starting date |
end_date | date | Ending date |
due_date | date | Due date |
status | string | The status of the statement (open or closed ) |
events_total | int | Sum of the events |
captures_total | int | Sum of the capture events |
refunds_total | int | Sum of the refund events |
payments_total | int | Sum of the payments |
opening_balance | int | Opening balance |
closing_balance | int | Closing balance |
events | list[event] | Events |
Events
An event is a post sale event that is linked to this Statement, see Post Sale event for more information
field | type | description |
---|---|---|
id | string(uuid) | API unique id for the event |
deferred_payment_id | string(uuid) | API unique id for the deferred payment |
organisation_id | string(uuid) | API unique if for the organisation |
organisation_name | string | |
captures_total | int | Sum of the capture events |
metadata | dict | Metadata that was sent with the post sale event |
created | datetime | Creation date |
amount | int | Amount of the event |
type | string | Type of the event (e.g. capture , refund , void , expiry , adjustment ) |
List Statement
Request
GET /v1/payment/billing_accounts/<billing_account_id>/statements HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/payment/billing_accounts/<billing_account_id>/statements \
--header "Content-Type: application/json" \
--header "Authorization: <your_api_key>"
Response
200 Ok
Content-Type: application/json
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": "st-ByVctXdbRa2nji7yUP4es3",
"public_id": "S-QHTQ-J3CB",
"start_date": "2023-12-01",
"end_date": "2023-12-31",
"due_date": "2024-01-10",
"status": "closed",
"total": null,
"events": []
}
]
}
List statement linked to your billing account.
Filters and ordering
You can order by:
- End date
GET /v1/payment/billing_accounts/<billing_account_id>/statements?ordering=end_date
- Due date
GET /v1/payment/billing_accounts/<billing_account_id>/statements?ordering=due_date
- Status
GET /v1/payment/billing_accounts/<billing_account_id>/statements?ordering=status
You can filter on:
- Status:
open
|closed
GET /v1/payment/billing_accounts/<billing_account_id>/statements?status=open
View statement
Requests
- request one statement
GET /v1/payment/billing_accounts/<billing_account_id>/statements/<statement_id> HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/payment/billing_accounts/<billing_account_id>/statements/<statement_id> \
--header "Authorization: <your_api_key>"
Responses
- Success response with optional expansion
200 Ok
Content-Type: application/json
{
"id": "st-Lt2q4F3jMhKCNpGAt9fhXM",
"public_id": "S-PGK2-DY55",
"start_date": "2023-09-01",
"end_date": "2023-09-30",
"due_date": "2023-10-20",
"status": "open",
"events_total": 5912,
"captures_total": 5912,
"refunds_total": 0,
"payments_total": 0,
"opening_balance": 0,
"closing_balance": null,
"events": [
{
"id": "dpevnt-ritfGaqfXaLJYGSbq8VHTd",
"deferred_payment_id": "defpay-2RzbCEGoerAqLhBT8cCdyX",
"organisation_id": "org-kFNAdsxqp8ChB2G5YSj9Cg",
"organisation_name": "Buyer Ltd",
"metadata": {
"note": "Capturing full amount",
"supplier_id": "4",
"supplier_ref": "44",
"supplier_name": "Another supplier",
"credit_note_ref": "4"
},
"created": "2023-09-12T14:38:27.196703Z",
"type": "capture",
"amount": 5912
}
]
}
- billing account/statement not found
404 Not Found
Content-Type: application/json
{
"detail": "Not found: BillingAccount `ba-MQP6PhT5F8PqMVWH4ANdT3` not found"
}
Errors
errors | description |
---|---|
404 | The billing_account_id is probably invalid, the billing account has not been found |
404 | The statement_id is probably invalid, the statement has not been found |
Statement document object
You can list the pdf and csv summary for a statement, those files are generated when the statement is closed.
{
"id": "sdoc-kS3sqRuDsb4SYH32sQPJjL",
"category": "summary_pdf",
"download_url": "..."
}
field | type | description |
---|---|---|
id | string(uuid) | API unique id for the document |
category | string | File category (summary_pdf or summary_csv ) |
download_url | string | Direct download url |
List Statement documents
Request
GET /v1/payment/billing_accounts/<billing_account_id>/statements/<statement_id>/documents HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/payment/billing_accounts/<billing_account_id>/statements/<statement_id>/documents \
--header "Content-Type: application/json" \
--header "Authorization: <your_api_key>"
Response
200 Ok
Content-Type: application/json
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": "sdoc-Vs4XkDNaoXLoQqWSwXRtXf",
"category": "summary_csv",
"download_url": "..."
},
{
"id": "sdoc-kS3sqRuDsb4SYH32sQPJjL",
"category": "summary_pdf",
"download_url": "..."
}
]
}
List statement documents generated when the statement was closed.
View Statement document
Request
GET /v1/payment/billing_accounts/<billing_account_id>/statements/<statement_id>/documents/<document_id> HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/payment/billing_accounts/<billing_account_id>/statements/<statement_id>/documents/<document_id> \
--header "Content-Type: application/json" \
--header "Authorization: <your_api_key>"
Response
200 Ok
Content-Type: application/json
{
"id": "sdoc-kS3sqRuDsb4SYH32sQPJjL",
"category": "summary_pdf",
"download_url": "..."
}
- Billing Account/Statement/Statement Document not found
404 Not Found
Content-Type: application/json
{
"detail": "Not found: Statement document `sdoc-kS3sqRuDsb4SYH32sQPJjL` not found"
}
Errors
errors | description |
---|---|
404 | The billing_account_id is probably invalid, the billing account has not been found |
404 | The statement_id is probably invalid, the statement has not been found |
404 | The statement_document_id is probably invalid, the statement document has not been found |
Orders
An order describes an instance of buying or selling something on your platform. An order consists of a basket of order items, plus details about the company making the purchase. Orders can be paid for at the time of the order or benefit from credit terms.
Orders serve two purposes in an integration with Hokodo:
a) Orders can be used to inform Hokodo about purchases the customer has made on your platform which Hokodo was not involved in. For example, you may have given the customer trade credit in the past, which has been successfully settled. Or the customer may have made purchases which were settled upfront (e.g. paid by card). Both of these are indicators which enhance our confidence that this is a genuine client and are favourable risk indicators. So providing Hokodo with data on these orders helps us to assess the customer's creditworthiness and to set the right credit limits for them.
b) You will also create an order when a customer shops on your platform so that you can obtain Deferred Payment Offers from Hokodo.
As we explain below, there are some commonalities between use cases a) and b) – for example in both cases we need to know who the buyer was, the value of the order, the date of the order etc. But there are also some differences. For example when you inform us about historical orders, you would tell us what payment terms were involved, whereas when you create an order for the purposes of getting deferred payment offers, Hokodo will be determining the payment terms via the offers we return.
Having more of the orders of the customers allows us to provide finer and higher credit limits, as well as reduce fraud.
Order endpoints
POST /v1/payment/orders
GET /v1/payment/orders
GET /v1/payment/orders/<order_id>
PATCH /v1/payment/orders/<order_id>
DELETE /v1/payment/orders/<order_id>
POST /v1/payment/orders/<order_id>/documents
GET /v1/payment/orders/<order_id>/documents/<document_id>
There are also legacy post-sale order endpoints described in a dedicated section:
PUT /v1/payment/orders/<order_id>/fulfill
PUT /v1/payment/orders/<order_id>/cancel
PUT /v1/payment/orders/<order_id>/return
PUT /v1/payment/orders/<order_id>/discount
PUT /v1/payment/orders/<order_id>/mark_disputed
Order object
{
"url": "https://api-sandbox.hokodo.co/v1/payment/orders/order-yQKxbtCg9aTS5JYnsRVA9B",
"id": "order-yQKxbtCg9aTS5JYnsRVA9B",
"unique_id": "876987-987uinjojna-I8UH98Jnj",
"customer": {
"organisation": "org-...",
"user": "user-...",
"type": "registered", # or "guest"
"delivery_address": {
"name": "John Smith",
"company_name": "",
"address_line1": "1 Station Street",
"address_line2": "Flat B",
"address_line3": "",
"city": "London",
"region": "",
"postcode": "SE11 6NQ",
"country": "GB",
"phone": "",
"email": ""
},
"invoice_address": {
"name": "John Smith",
"address_line1": "1 Station Street",
"address_line2": "Flat B",
"city": "London",
"postcode": "SE11 6NQ",
"country": "GB"
}
},
"status": "pending",
"pay_method": "card",
"currency": "GBP",
"total_amount": 12000, # total amount including tax
"tax_amount": 2000, # tax amount
"order_date": "2018-04-25",
"invoice_date": "2018-04-25",
"due_date": "2018-05-25",
"paid_date": "2018-05-27",
"items": [
{
"item_id": "1",
"type": "product", # or discount, shipping, etc.
"description": "Super ergonomic chair",
"metadata": {"color": "black", "name": "Karmus", "variant": "M"},
"reference": "702.611.50",
"category": "Furniture > Chairs",
"supplier_id": "7363",
"supplier_name": "Cool chair wholesaler",
"quantity": "10.000",
"unit_price": 1000, # includes tax
"tax_rate": "20.00",
"total_amount": 10000,
"tax_amount": 2000,
"fulfilled_quantity": 0,
"fulfillment_info": null,
"cancelled_quantity": 0,
"cancelled_info": null,
"returned_quantity": 0,
"returned_info": null
},
{
"item_id": "2",
"type": "shipping",
"description": "Delivery fee",
"quantity": "1.000",
"unit_price": 2000,
"tax_rate": "20.00",
"total_amount": 2000,
"tax_amount": 400,
"fulfilled_quantity": 0,
"fulfillment_info": null,
"cancelled_quantity": 0,
"cancelled_info": null,
"returned_quantity": 0,
"returned_info": null
}
],
"metadata": {}, # store key-values for your internal references
"po_number": "P-45612",
"payment_offer": null,
"deferred_payment": null
}
The Order object contains many fields that are optional for historical orders. See below for an example of a minimal historical order.
field | type | flags | description |
---|---|---|---|
url | string | read-only | API endpoint to access the order |
id | string(uuid) | read-only | API unique identifier for the order |
unique_id | string | required | Unique identifier of the order in your platform |
customer | dictionary | required | Customer making the order (see guest/registered users) |
customer[type] | string | required | "registered" or "guest" |
customer[organisation] | string(uuid) | required | API unique identifier of the organisation of the customer (if registered) (can be expanded to a full Organisation object) |
customer[user] | string(uuid) | required | API unique identifier of the user of the customer (if registered) (can be expanded to a full User object) |
customer[delivery_address] | dictionary | required | Delivery/shipping address for this order. See Addresses for a description of the fields |
customer[invoice_address] | dictionary | required | Invoice (or Billing) address for this order. See Addresses for a description of the fields |
status | string | required | Order status |
(deprecated) pay_method | string | optional | Used to supply the Payment method, only if the order has already been paid without Hokodo |
currency | currency (ISO 4217 code) | required | Currency of order amounts |
tax_amount | int | required | Total amount of the taxes, in minor units (cents) |
total_amount | int | required | Total amount including tax, in minor units (cents) |
order_date | date | optional | Date of the order |
invoice_date | date | optional | Date of issuance of the invoice, if different from order date |
due_date | date | optional | Date due of the order (assuming the customer was given credit terms – if no credit terms were offered, then this would simply be the order_date ) |
paid_date | date | optional | Date when the order was paid in full (assuming credit terms were offered – otherwise this would simply be the order_date ) |
items | list | required | The list of items that constitute the order |
items[*][item_id] | string | required | Your identifier for this line of the order, e.g. 1, 2, 3... |
items[*][type] | string | required | Type of the item. Can be one of the following: product, service, digital, shipping, fee, discount |
items[*][description] | string | required | Description of the item |
items[*][metadata] | dictionary | optional | Key-value pairs attached to the item, for example describing the color, variant, specific options, to help identify the item post-sale |
items[*][reference] | string | optional | Item reference number, SKU, etc. |
items[*][category] | string | optional | Category of the item, as per owner's internal classification |
items[*][supplier_id] | string | optional | An id of the supplier of the items (if applicable), can be your internal identifier of the supplier, for example "152" |
items[*][supplier_name] | string | optional | The name of the supplier of the items (if applicable) |
items[*][quantity] | decimal | required | Number of items in the order |
items[*][unit_price] | int | required | Price of a single unit, including tax, in minor units (cents) |
items[*][tax_rate] | decimal | required | Tax rate on this item, in percent (e.g. "19.50" for 19.5%) |
items[*][tax_amount] | int | required | Amount of the tax for this item, in minor units (cents) |
items[*][total_amount] | int | required | Total amount for this item, including tax, in minor units (cents) |
items[*][fulfilled_quantity] | decimal | read-only | Number of items fulfilled |
items[*][fulfillment_info] | list | read-only | Information about shipping of the items (see section Fulfillment) |
items[*][fulfillment_info][*][quantity] | decimal | read-only | Number of items in the shipment |
items[*][fulfillment_info][*][shipping_id] | string | read-only | Tracking id when the item has shipped (add when shipped) |
items[*][fulfillment_info][*][shipping_provider] | string | read-only | Name of the shipping provider (add when shipped) |
items[*][cancelled_quantity] | decimal | read-only | Number of items cancelled |
items[*][cancelled_info] | list | read-only | Information about cancellation of the items (see section Cancellation) |
items[*][cancelled_info][*][quantity] | decimal | read-only | Quantity of items cancelled |
items[*][cancelled_info][*][total_amount] | string | read-only | Total value of items cancelled |
items[*][cancelled_info][*][tax_amount] | string | read-only | Total tax amount of items cancelled |
items[*][returned_quantity] | decimal | read-only | Number of items returned |
items[*][returned_info] | list | read-only | Information about items returned (see section Returns) |
items[*][returned_info][*][quantity] | decimal | read-only | Number of items returned |
items[*][returned_info][*][total_amount] | string | read-only | Total value of items returned |
items[*][returned_info][*][tax_amount] | string | read-only | Total tax amount of items returned |
metadata | dictionary | optional | Set of key-value pairs you can attach to the object. You can use this to store your custom data in the object and read it back later. |
po_number | string | optional | Purchase order number from the customer (for their benefit, as reference) |
payment_offer | string(uuid) | read-only | API unique identifier for the deferred payment offer (if created, can be expanded to a full Payment Offer object) |
deferred_payment | string(uuid) | read-only | API unique identifier for the deferred payment in place (if created, can be expanded to a full Deferred payment object) |
Order status
The order status
must be one of:
draft
, meaning the customer has not yet made the purchase, more information belowunpaid
, meaning the purchase has been completed, but not yet paid for - or at least not paid in full (typically because the customer has been given credit terms and has not yet settled)paid
, meaning the order has been settled in fullcancelled
, meaning the order has been cancelled (e.g. associated DeferredPayment authorisation entirely voided)disputed
, meaning the customer has not yet settled in full because they have raised a dispute about whether/how much they owe, which has not yet been resolved
On draft orders
Draft order status can be used for orders that the user has not yet committed to, e.g. they put something in their cart
but did not yet complete the checkout. If the customer goes on to pay via a payment method other than Hokodo Deferred
Payment (e.g. they pay by card) then you should amend the order status to paid
. In this case the paid order becomes
part of the payment history that Hokodo can take into account when assessing this customer for Deferred Payment in the
future.
If the customer abandons the checkout and so never completes the purchase, then the order will remain in draft
status,
and so we will know not to include it in any analysis of the customer's historical payment behaviour.
If the customer ends up completing the purchase using a Hokodo Deferred Payment, then we will automatically move the
status to unpaid
, and ultimately to paid
.
(Deprecated) Payment method
The pay_method
must be one of:
unknown
, when payment method is not determinedbank
, for a bank transfer sent by the customercard
, for credit/debit cardcash
, for cash
Please contact us to add more payment methods for purchases not made via Hokodo, to match closely your platform. This information helps us to provide finer and higher credit limits.
Guest users / registered users
Hokodo needs to identify the customer and their company to be able to provide deferred payments, whether they are a registered and logged-in user on your platform, or they are a guest user making a single purchase.
Both cases require a User and Organisation. For registered users, this will be a one-time creation. For guests users, you can re-use a User and Organisation you have already created, or create a fresh one each time.
This flow will work the same for both guest users and registered users:
Create User with the email address of the user (which may be an unverified email address for guest customers)
User uniqueness on Hokodo's side is based on email address. If we detect that they have already been registered as a User on your platform, Hokodo API will return the existing user and identifier, complete with links to Organisation and Company saved before.
If no organisation was linked to the user, or they wish to link a different one, search and identify the company via company search.
Create the Organisation linked to that Company.
Attach the User to the Organisation.
Registered user
If the customer is a registered user on your platform, you should create or
have created an Organisation (to represent their team /
company), and a User (to represent the individuals within that team /
company). Then, use that organisation
and user
in the customer
field of
the Order.
Registered user
{
"customer": {
"organisation": "...",
"user": "...",
"type": "registered",
"delivery_address": {
"...": "..."
}
}
}
Guest user
If the customer is a guest user, and has not registered on your platform, you should
collect some information to help us identify the customer, and create a User
and Organisation in the same way as for registered user. When you
create the User
object, Hokodo may return an existing User object, if you had
previously created a User with the same email address. In that case, it may also
have the correct Organisation filled in already.
Guest user
{
"customer": {
"organisation": "...",
"user": "...",
"type": "guest",
"delivery_address": {
"...": "..."
}
}
}
Addresses
{
"name": "John Smith",
"company_name": "",
"address_line1": "1 Station Street",
"address_line2": "Flat B",
"address_line3": "",
"city": "London",
"region": "",
"postcode": "SE11 6NQ",
"country": "GB",
"phone": "",
"email": ""
}
The fields used in addresses are:
field | type | flags | description |
---|---|---|---|
name | string | required | Full name |
company_name | string | optional | (for delivery) Name of the company for delivery if it differs from the legal entity's name |
address_line1 | string | required | Line 1 of the address |
address_line2 | string | optional | Line 2 of the address |
address_line3 | string | optional | Line 3 of the address |
city | string | required | City |
region | string | optional | State or Region |
postcode | string | required | Postal/ZIP code |
country | country | required | Country code |
phone | string | optional | Phone number associated to the address (eg to handle delivery) |
string | optional | Email associated to the address (eg to handle delivery notifications) |
Create order
Requests
- minimal historical order of a registered user
POST /v1/payment/orders HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
{
"unique_id": "876987-987uinjojna-I8UH98Jnj",
"customer": {
"type": "registered",
"organisation": "org-ypTaHiLv5kgqSn4TzCr7xb",
"user": "user-nNqgg5AFymQMumaU7EdrLa",
"delivery_address": {
"name": "John Smith",
"address_line1": "1 Station Street",
"address_line2": "Flat B",
"city": "London",
"postcode": "SE11 6NQ",
"country": "GB"
},
"invoice_address": {
"name": "John Smith",
"address_line1": "1 Station Street",
"address_line2": "Flat B",
"city": "London",
"postcode": "SE11 6NQ",
"country": "GB"
},
},
"status": "paid",
"currency": "GBP",
"total_amount": 12000,
"tax_amount": 2000,
"order_date": "2018-04-25",
"invoice_date": "2018-04-25",
"due_date": "2018-05-25",
"paid_date": "2018-06-10",
"pay_method": "card"
}
curl --request POST \
--url https://api-sandbox.hokodo.co/v1/payment/orders \
--header "Content-Type: application/json" \
--header "Authorization: <your_api_key>" \
--data-binary '{
"unique_id": "876987-987uinjojna-I8UH98Jnj",
"customer": {
"type": "registered",
"organisation": "org-ypTaHiLv5kgqSn4TzCr7xb",
"user": "user-nNqgg5AFymQMumaU7EdrLa",
"delivery_address": {
"name": "John Smith",
"address_line1": "1 Station Street",
"address_line2": "Flat B",
"city": "London",
"postcode": "SE11 6NQ",
"country": "GB"
},
"invoice_address": {
"name": "John Smith",
"address_line1": "1 Station Street",
"address_line2": "Flat B",
"city": "London",
"postcode": "SE11 6NQ",
"country": "GB"
},
},
"status": "paid",
"currency": "GBP",
"total_amount": 12000,
"tax_amount": 2000,
"order_date": "2018-04-25",
"invoice_date": "2018-04-25",
"due_date": "2018-05-25",
"paid_date": "2018-06-10",
"pay_method": "card"
}'
- new order of a registered user
POST /v1/payment/orders HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
{
"unique_id": "876987-987uinjojna-I8UH98Jnj",
"customer": {
"type": "registered",
"organisation": "org-ypTaHiLv5kgqSn4TzCr7xb",
"user": "user-nNqgg5AFymQMumaU7EdrLa",
"delivery_address": {
"name": "John Smith",
"address_line1": "1 Station Street",
"address_line2": "Flat B",
"city": "London",
"postcode": "SE11 6NQ",
"country": "GB"
},
},
"status": "draft",
"currency": "GBP",
"total_amount": 12000,
"tax_amount": 2000,
"order_date": "2018-04-25",
"items": [
{
"item_id": "1",
"type": "product",
"description": "Super ergonomic chair",
"metadata": {"color": "black", "name": "Karmus", "variant": "M"},
"reference": "702.611.50",
"category": "Furniture > Chairs",
"supplier_id": "7363",
"quantity": "10.000",
"unit_price": 1000,
"tax_rate": "20.00",
"total_amount": 10000,
"tax_amount": 2000,
"fulfilled_quantity": 0,
"fulfillment_info": null,
"cancelled_quantity": 0,
"cancelled_info": null,
"returned_quantity": 0,
"returned_info": null
},
{
"item_id": "2",
"type": "shipping",
"description": "Delivery fee",
"quantity": "1.000",
"unit_price": 2000,
"tax_rate": "20.00",
"total_amount": 2000,
"tax_amount": 400,
"fulfilled_quantity": 0,
"fulfillment_info": null,
"cancelled_quantity": 0,
"cancelled_info": null,
"returned_quantity": 0,
"returned_info": null
}
],
"metadata": {
"customer_id": "2055b445-3d95-4d2f-bd80-3e336217905f",
"checkout_id": "c0185e68-89aa-42d5-93e9-476d01d4c97f"
}
}
curl --request POST \
--url https://api-sandbox.hokodo.co/v1/payment/orders \
--header "Content-Type: application/json" \
--header "Authorization: <your_api_key>" \
--data-binary '{
"unique_id": "876987-987uinjojna-I8UH98Jnj",
"customer": {
"type": "registered",
"organisation": "org-ypTaHiLv5kgqSn4TzCr7xb",
"user": "user-nNqgg5AFymQMumaU7EdrLa",
"delivery_address": {
"name": "John Smith",
"address_line1": "1 Station Street",
"address_line2": "Flat B",
"city": "London",
"postcode": "SE11 6NQ",
"country": "GB"
},
},
"status": "draft",
"currency": "GBP",
"total_amount": 12000,
"tax_amount": 2000,
"order_date": "2018-04-25",
"items": [
{
"item_id": "1",
"type": "product",
"description": "Super ergonomic chair",
"metadata": {"color": "black", "name": "Karmus", "variant": "M"},
"reference": "702.611.50",
"category": "Furniture > Chairs",
"supplier_id": "7363",
"quantity": "10.000",
"unit_price": 1000,
"tax_rate": "20.00",
"total_amount": 10000,
"tax_amount": 1667
},
{
"item_id": "2",
"type": "shipping",
"description": "Delivery fee",
"quantity": "1.000",
"unit_price": 2000,
"tax_rate": "20.00",
"total_amount": 2000,
"tax_amount": 333
}
],
"metadata": {
"customer_id": "2055b445-3d95-4d2f-bd80-3e336217905f",
"checkout_id": "c0185e68-89aa-42d5-93e9-476d01d4c97f"
}
}'
- new order of a guest user
POST /v1/payment/orders HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
{
"unique_id": "876987-987uinjojna-I8UH98Jnj",
"customer": {
"type": "guest",
"organisation": "org-ypTaHiLv5kgqSn4TzCr7xb",
"user": "user-nNqgg5AFymQMumaU7EdrLa",
"delivery_address": {
"name": "John Smith",
"address_line1": "1 Station Street",
"address_line2": "Flat B",
"city": "London",
"postcode": "SE11 6NQ",
"country": "GB"
},
},
"status": "draft",
"currency": "GBP",
"total_amount": 12000,
"tax_amount": 2000,
"order_date": "2018-04-25",
"items": [
{
"item_id": "1",
"type": "product",
"description": "Super ergonomic chair",
"metadata": {"color": "black", "name": "Karmus", "variant": "M"},
"reference": "702.611.50",
"category": "Furniture > Chairs",
"supplier_id": "7363",
"quantity": "10.000",
"unit_price": 1000,
"tax_rate": "20.00",
"total_amount": 10000,
"tax_amount": 2000,
"fulfilled_quantity": 0,
"fulfillment_info": null,
"cancelled_quantity": 0,
"cancelled_info": null,
"returned_quantity": 0,
"returned_info": null
},
{
"item_id": "2",
"type": "shipping",
"description": "Delivery fee",
"quantity": "1.000",
"unit_price": 2000,
"tax_rate": "20.00",
"total_amount": 2000,
"tax_amount": 400,
"fulfilled_quantity": 0,
"fulfillment_info": null,
"cancelled_quantity": 0,
"cancelled_info": null,
"returned_quantity": 0,
"returned_info": null
}
],
"metadata": {
"customer_id": "2055b445-3d95-4d2f-bd80-3e336217905f",
"checkout_id": "c0185e68-89aa-42d5-93e9-476d01d4c97f"
}
}
curl --request POST \
--url https://api-sandbox.hokodo.co/v1/payment/orders \
--header "Content-Type: application/json" \
--header "Authorization: <your_api_key>" \
--data-binary '{
"unique_id": "876987-987uinjojna-I8UH98Jnj",
"customer": {
"type": "registered",
"company": "org-QdKZ5mdD8BrG5CKxGok2Q4",
"email": "john@example.com",
"name": "John Smith",
"phone": "+44 123 456 7890",
"delivery_address": {
"name": "John Smith",
"address_line1": "1 Station Street",
"address_line2": "Flat B",
"city": "London",
"postcode": "SE11 6NQ",
"country": "GB"
},
},
"status": "draft",
"currency": "GBP",
"total_amount": 12000,
"tax_amount": 2000,
"order_date": "2018-04-25",
"items": [
{
"item_id": "1",
"type": "product",
"description": "Super ergonomic chair",
"metadata": {"color": "black", "name": "Karmus", "variant": "M"},
"reference": "702.611.50",
"category": "Furniture > Chairs",
"supplier_id": "7363",
"quantity": "10.000",
"unit_price": 1000,
"tax_rate": "20.00",
"total_amount": 10000,
"tax_amount": 1667
},
{
"item_id": "2",
"type": "shipping",
"description": "Delivery fee",
"quantity": "1.000",
"unit_price": 2000,
"tax_rate": "20.00",
"total_amount": 2000,
"tax_amount": 333
}
],
"metadata": {
"customer_id": "2055b445-3d95-4d2f-bd80-3e336217905f",
"checkout_id": "c0185e68-89aa-42d5-93e9-476d01d4c97f"
}
}'
Responses
- success response
201 Created
Content-Type: application/json
{
"url": "https://api-sandbox.hokodo.co/v1/payment/orders/order-yQKxbtCg9aTS5JYnsRVA9B",
"id": "order-yQKxbtCg9aTS5JYnsRVA9B",
"unique_id": "48b0ce9a-f8a3-4dff-be56-26af747b3d98",
"customer": {
"type": "registered",
"organisation": "org-ypTaHiLv5kgqSn4TzCr7xb",
"user": "user-nNqgg5AFymQMumaU7EdrLa",
"delivery_address": {
"name": "John Smith",
"address_line1": "1 Station Street",
"address_line2": "Flat B",
"address_line3": "",
"city": "London",
"region": "",
"postcode": "SE11 6NQ",
"country": "GB",
"phone": "",
"email": ""
}
},
"status": "draft",
"currency": "GBP",
"pay_method": "",
"total_amount": 12000,
"tax_amount": 2000,
"order_date": "2018-04-25",
"invoice_date": null,
"due_date": null,
"paid_date": null,
"items": [
{
"item_id": "1",
"type": "product",
"description": "Super ergonomic chair",
"metadata": {"color": "black", "name": "Karmus", "variant": "M"},
"reference": "702.611.50",
"category": "Furniture > Chairs",
"supplier_id": "7363",
"supplier_name": "",
"quantity": "10.000",
"unit_price": 1000,
"tax_rate": "20.00",
"total_amount": 10000,
"tax_amount": 2000,
"fulfilled_quantity": 0,
"fulfillment_info": null,
"cancelled_quantity": 0,
"cancelled_info": null,
"returned_quantity": 0,
"returned_info": null
},
{
"item_id": "2",
"type": "shipping",
"description": "Delivery fee",
"metadata": {},
"reference": "",
"category": "",
"supplier_id": "",
"supplier_name": "",
"quantity": "1.000",
"unit_price": 2000,
"tax_rate": "20.00",
"total_amount": 2000,
"tax_amount": 400,
"fulfilled_quantity": 0,
"fulfillment_info": null,
"cancelled_quantity": 0,
"cancelled_info": null,
"returned_quantity": 0,
"returned_info": null
}
],
"metadata": {
"customer_id": "2055b445-3d95-4d2f-bd80-3e336217905f",
"checkout_id": "c0185e68-89aa-42d5-93e9-476d01d4c97f"
},
"payment_offer": null,
"deferred_payment": null
}
- error response (example)
400 Bad Request
Content-Type: application/json
{
"organisation": [
"Invalid pk \"org-AgBGknk7D8KixY2ntbJtmA\" - object does not exist."
],
"user": [
"Bad prefix. Expected a UUID prefixed by \"user\", but got xyz."
],
"items": [
{
"total_amount": "Item 1 unit_price [1084] and quantity [10.000] does not match total_amount [13010]."
}
]
}
To create an order, you create an Order
object.
Many fields are optional. However, to obtain a Deferred Payment Offer later the system must be provided with the following information at least:
- A way to identify the customer (whether they're registered and logged in, or a guest)
- The order amount and currency
- The order date of the invoice
- The list of items constituting this order, including shipping and any other charges as separate line items
The more information is provided at order creation, the more accurate the Payment Offer Hokodo can provide, and the less friction there will be for your customer later on to complete the purchase.
Errors
errors | description |
---|---|
400 | a required field is missing or some of the fields have incorrect value |
List orders
Request
GET /v1/payment/orders HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/payment/orders \
--header "Content-Type: application/json" \
--header "Authorization: <your_api_key>"
Response
200 Ok
Content-Type: application/json
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"url": "https://api-sandbox.hokodo.co/v1/payment/orders/order-yQKxbtCg9aTS5JYnsRVA9B",
"id": "order-yQKxbtCg9aTS5JYnsRVA9B",
"unique_id": "48b0ce9a-f8a3-4dff-be56-26af747b3d98",
"customer": {
"type": "registered",
"organisation": "org-ypTaHiLv5kgqSn4TzCr7xb",
"user": "user-nNqgg5AFymQMumaU7EdrLa",
"delivery_address": {
"name": "John Smith",
"address_line1": "1 Station Street",
"address_line2": "Flat B",
"address_line3": "",
"city": "London",
"region": "",
"postcode": "SE11 6NQ",
"country": "GB",
"phone": "",
"email": ""
}
},
"status": "draft",
"currency": "GBP",
"pay_method": "",
"total_amount": 12000,
"tax_amount": 2000,
"order_date": "2018-04-25",
"invoice_date": null,
"due_date": null,
"paid_date": null,
"items": [
{
"item_id": "1",
"type": "product",
"description": "Super ergonomic chair",
"metadata": {"color": "black", "name": "Karmus", "variant": "M"},
"reference": "702.611.50",
"category": "Furniture > Chairs",
"supplier_id": "7363",
"supplier_name": "",
"quantity": "10.000",
"unit_price": 1000,
"tax_rate": "20.00",
"total_amount": 10000,
"tax_amount": 2000,
"fulfilled_quantity": 0,
"fulfillment_info": null,
"cancelled_quantity": 0,
"cancelled_info": null,
"returned_quantity": 0,
"returned_info": null
},
{
"item_id": "2",
"type": "shipping",
"description": "Delivery fee",
"metadata": {},
"reference": "",
"category": "",
"supplier_id": "",
"supplier_name": "",
"quantity": "1.000",
"unit_price": 2000,
"tax_rate": "20.00",
"total_amount": 2000,
"tax_amount": 400,
"fulfilled_quantity": 0,
"fulfillment_info": null,
"cancelled_quantity": 0,
"cancelled_info": null,
"returned_quantity": 0,
"returned_info": null
}
],
"metadata": {
"customer_id": "2055b445-3d95-4d2f-bd80-3e336217905f",
"checkout_id": "c0185e68-89aa-42d5-93e9-476d01d4c97f"
},
"payment_offer": null,
"deferred_payment": null
},
{
"url": "https://api-sandbox.hokodo.co/v1/payment/orders/order-LitFGLodQh9qQHTFcjUvfm",
"id": "order-LitFGLodQh9qQHTFcjUvfm",
"unique_id": "8751729d-7e96-4d38-87bc-fe241ca1d4d7",
"customer": {
"type": "registered",
"organisation": "org-dLWYumjHaqChNggScx5inV",
"user": "user-czNtrBwLY63rJkqmgyQaEF",
"delivery_address": {
"name": "John Smith",
"address_line1": "1 Station Street",
"address_line2": "Flat B",
"address_line3": "",
"city": "London",
"region": "",
"postcode": "SE11 6NQ",
"country": "GB",
"phone": "",
"email": ""
}
},
"status": "draft",
"currency": "GBP",
"pay_method": "",
"total_amount": 12000,
"tax_amount": 2000,
"order_date": "2018-04-25",
"invoice_date": null,
"due_date": null,
"paid_date": null,
"items": [
{
"item_id": "1",
"type": "product",
"description": "Super ergonomic chair",
"metadata": {"color": "black", "name": "Karmus", "variant": "M"},
"reference": "702.611.50",
"category": "Furniture > Chairs",
"supplier_id": "7363",
"supplier_name": "",
"quantity": "10.000",
"unit_price": 1000,
"tax_rate": "20.00",
"total_amount": 10000,
"tax_amount": 2000,
"fulfilled_quantity": 0,
"fulfillment_info": null,
"cancelled_quantity": 0,
"cancelled_info": null,
"returned_quantity": 0,
"returned_info": null
},
{
"item_id": "2",
"type": "shipping",
"description": "Delivery fee",
"metadata": {},
"reference": "",
"category": "",
"supplier_id": "",
"supplier_name": "",
"quantity": "1.000",
"unit_price": 2000,
"tax_rate": "20.00",
"total_amount": 2000,
"tax_amount": 400,
"fulfilled_quantity": 0,
"fulfillment_info": null,
"cancelled_quantity": 0,
"cancelled_info": null,
"returned_quantity": 0,
"returned_info": null
}
],
"metadata": {
"customer_id": "584eaf27-250c-4b83-826f-909cbaa1f54a",
"checkout_id": "59e278cd-305a-4bbe-a275-f038f9319b1c"
},
"payment_offer": null,
"deferred_payment": null
}
]
}
List orders created by your platform
View order
Requests
- without expanding referenced objects
GET /v1/payment/orders/<order_id> HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/payment/orders/<order_id> \
--header "Authorization: <your_api_key>"
- with expanding referenced customer, payment_offer
GET /v1/payment/orders/<order_id>?expand=customer,payment_offer HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/payment/orders/<order_id>?expand=customer,payment_offer \
--header "Content-Type: application/json" \
--header "Authorization: <your_api_key>"
Responses
- regular response (with optional expansion)
200 Ok
Content-Type: application/json
{
"url": "https://api-sandbox.hokodo.co/v1/payment/orders/order-yQKxbtCg9aTS5JYnsRVA9B",
"id": "order-yQKxbtCg9aTS5JYnsRVA9B",
"unique_id": "48b0ce9a-f8a3-4dff-be56-26af747b3d98",
"customer": {
"type": "registered",
"organisation": {
"id": "org-ypTaHiLv5kgqSn4TzCr7xb",
"unique_id": "c105b862-f1ba-4197-9d97-57db63196b00",
"registered": "2022-06-01T14:37:12Z",
"name": "Organisation name",
"company": {
"url": "https://api-sandbox.hokodo.co/v1/companies/co-Toq88Ko9RKoukP9AagxJoM",
"id": "co-Toq88Ko9RKoukP9AagxJoM",
"country": "GB",
"name": "Hokodo Ltd",
"address": "35 Kingsland Road, London, E2 8AA",
"city": "London",
"postcode": "E2 8AA",
"legal_form": "Private limited with share capital",
"sectors": [
{
"system": "SIC2007",
"code": "64999"
}
],
"creation_date": "2018-02-20",
"identifiers": [
{
"idtype": "reg_number",
"country": "GB",
"value": "11215527"
}
],
"email": "hokodo@hokodo.co",
"phone": "",
"status": "Active",
"accounts_type": "Active"
},
"users": [
"d1696bbe-e982-4065-ac84-3e6543f4da24",
"3ae2713d-e79a-4837-8cef-06af956af3b9"
]
},
"user": {
"id": "user-CXavtWTgLxU7rNuSzkyKDX",
"email": "a_mail@example.com",
"unique_id": "",
"name": "A name",
"phone": "+44123456789",
"registered": "2018-07-01T12:12:12Z",
"type": "registered"
},
"invoice_address": {
"name": "Bob Accounting",
"company_name": "",
"address_line1": "1 Main Street",
"address_line2": "65th floor",
"address_line3": "",
"city": "London",
"region": "",
"postcode": "SE11 6NQ",
"country": "GB",
"phone": "",
"email": ""
},
"delivery_address": {
"name": "John Smith",
"address_line1": "1 Station Street",
"address_line2": "Flat B",
"address_line3": "",
"city": "London",
"region": "",
"postcode": "SE11 6NQ",
"country": "GB",
"phone": "",
"email": ""
}
},
"status": "draft",
"currency": "GBP",
"pay_method": "",
"total_amount": 12000,
"tax_amount": 2000,
"order_date": "2018-04-25",
"invoice_date": null,
"due_date": null,
"paid_date": null,
"items": [
{
"item_id": "1",
"type": "product",
"description": "Super ergonomic chair",
"metadata": {"color": "black", "name": "Karmus", "variant": "M"},
"reference": "702.611.50",
"category": "Furniture > Chairs",
"supplier_id": "7363",
"supplier_name": "",
"quantity": "10.000",
"unit_price": 1000,
"tax_rate": "20.00",
"total_amount": 10000,
"tax_amount": 2000,
"fulfilled_quantity": 0,
"fulfillment_info": null,
"cancelled_quantity": 0,
"cancelled_info": null,
"returned_quantity": 0,
"returned_info": null
},
{
"item_id": "2",
"type": "shipping",
"description": "Delivery fee",
"metadata": {},
"reference": "",
"category": "",
"supplier_id": "",
"supplier_name": "",
"quantity": "1.000",
"unit_price": 2000,
"tax_rate": "20.00",
"total_amount": 2000,
"tax_amount": 400,
"fulfilled_quantity": 0,
"fulfillment_info": null,
"cancelled_quantity": 0,
"cancelled_info": null,
"returned_quantity": 0,
"returned_info": null
}
],
"metadata": {
"customer_id": "2055b445-3d95-4d2f-bd80-3e336217905f",
"checkout_id": "c0185e68-89aa-42d5-93e9-476d01d4c97f"
},
"payment_offer": {
"url": "https://api-sandbox.hokodo.co/v1/payment/offers/offer-EzH6BixNSHvaByEpXcFW5h",
"id": "offer-bqRyHAGaFrDEN8JNjXJirp",
"order": "order-dTHo9Q2idffT7CMPCVjztA",
"offered_payment_plans": [
{
"id": "ppln-bqRyHAGaFrDEN8JNjXJirp",
"name": "net30",
"template": "pptemp-RySHMoFqSxfmkcfrYC2VeF",
"currency": "GBP",
"protected_amount": 100000,
"unprotected_amount": 0,
"scheduled_payments": [
{
"date": "2020-10-16",
"amount": 100000,
"discounted_amount": 100000,
"customer_fee": {
"percentage": "0.00",
"amount": 0
},
"allowed_payment_methods": [
{"type": "card", "providers": ["card_provider_name"]},
{"type": "direct_debit", "providers": ["dd_provider_name"]},
{"type": "bank_transfer", "providers": ["bt_provider_name"]}
],
"allowed_payment_method_types": [
{"type": "card", "providers": ["card_provider_name"]},
{"type": "direct_debit", "providers": ["dd_provider_name"]},
{"type": "bank_transfer", "providers": ["bt_provider_name"]}
],
"payment_method": {
"type": "card",
"card": {
"brand": "mastercard",
"exp_month": 4,
"exp_year": 2044,
"last4": "1375"
}
},
"due_date_config": {
"due_after_nb_days": 30,
"due_end_of_nb_months": null,
"amount_percentage": "100.0",
"is_upfront_payment": false
}
}
],
"payment_terms_relative_to": "order_creation",
"merchant_fee": {
"currency": "GBP",
"amount": 1000
},
"customer_fee": {
"currency": "GBP",
"percentage": "0.00",
"amount": 0
},
"customer_percentage_discount": "0.00",
"customer_discount": {
"currency": "EUR",
"amount": 0
},
"valid_until": "2020-09-16T12:44:49.059Z",
"payment_url": "https://payment.app.hokodo.co/plans/ppln-bqRyHAGaFrDEN8JNjXJirp",
"status": "active",
"rejection_reason": null,
"has_upfront_payment": false
},
{
"id": "ppln-gJdDHAGaFrDLDvJNXJird",
"name": "4xEOM",
"template": "pptemp-RySHMoFqSxfmkcfrYC2VeF",
"currency": "GBP",
"protected_amount": 100400,
"unprotected_amount": 0,
"scheduled_payments": [
{
"date": "2020-09-30",
"amount": 25100,
"discounted_amount": 25100,
"customer_fee": {
"percentage": "0.40",
"amount": 100
},
"allowed_payment_methods": [
{"type": "card", "providers": ["card_provider_name"]}
],
"payment_method": null,
"due_date_config": {
"due_after_nb_days": 30,
"due_end_of_nb_months": null,
"amount_percentage": "25.0",
"is_upfront_payment": false
}
},
{
"date": "2020-10-31",
"amount": 25100,
"discounted_amount": 25100,
"customer_fee": {
"percentage": "0.40",
"amount": 100
},
"allowed_payment_methods": [
{"type": "card", "providers": ["card_provider_name"]}
],
"payment_method": null,
"due_date_config": {
"due_after_nb_days": null,
"due_end_of_nb_months": 1,
"amount_percentage": "25.0",
"is_upfront_payment": false
}
},
{
"date": "2020-11-30",
"amount": 25100,
"discounted_amount": 25100,
"customer_fee": {
"percentage": "0.40",
"amount": 100
},
"allowed_payment_methods": [
{"type": "card", "providers": ["card_provider_name"]}
],
"payment_method": null,
"due_date_config": {
"due_after_nb_days": null,
"due_end_of_nb_months": 2,
"amount_percentage": "25.0",
"is_upfront_payment": false
}
},
{
"date": "2020-12-31",
"amount": 25100,
"discounted_amount": 25100,
"customer_fee": {
"percentage": "0.40",
"amount": 100
},
"allowed_payment_methods": [
{"type": "card", "providers": ["card_provider_name"]}
],
"payment_method": null,
"due_date_config": {
"due_after_nb_days": null,
"due_end_of_nb_months": 3,
"amount_percentage": "25.0",
"is_upfront_payment": false
}
}
],
"payment_terms_relative_to": "order_creation",
"merchant_fee": {
"currency": "GBP",
"amount": 2000
},
"customer_fee": {
"currency": "GBP",
"percentage": "0.40",
"amount": 400
},
"customer_percentage_discount": "0.00",
"customer_discount": {
"currency": "EUR",
"amount": 0
},
"valid_until": "2020-09-16T12:44:49.059Z",
"payment_url": "https://payment.app.hokodo.co/plans/ppln-gJdDHAGaFrDLDvJNXJird",
"status": "active",
"rejection_reason": null,
"has_upfront_payment": false
}
],
"urls": {
"success": "https://merchant.com/payment/ok",
"failure": "https://merchant.com/checkout",
"cancel": "https://merchant.com/checkout",
"notification": "https://backend.merchant.com/payment/notifications",
"merchant_terms": "https://merchant.com/terms"
},
"locale": "en-gb",
"metadata": {}
},
"deferred_payment": null
}
- order not found
404 Not Found
Content-Type: application/json
{
"detail": "Not found."
}
Look up a previously created order.
Errors
errors | description |
---|---|
404 | the order_id is probably invalid, the order has not been found |
Modify order
Modify a previously created order.
Historic Orders
When you supply information on Orders for the purposes of informing Hokodo about a customer's payment history, you are able to amend those orders freely, or even delete them using the Delete Order endpoint.
Orders with a PaymentOffer
Once you request a PaymentOffer for an Order, any subsequent changes made to the Order will automatically expire the PaymentOffer.
Note: You can still amend the following fields unique_id
, metadata
, po_number
as they don't affect the terms
of the PaymentOffer.
Orders with a DeferredPayment
Once the customer purchases a DeferredPayment, the underlying Order can no longer be amended using the Order's endpoint,
with the following exception: unique_id
. Instead, you must use the dedicated endpoints for dealing with Cancellations,
Refunds/Discounts and Returns, which are described in the post-sale Order actions section.
Request (e.g. update when an invoice has been paid)
PATCH /v1/payment/orders/<order_id> HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
{
"status": "paid",
"paid_date": "2018-06-10",
"pay_method": "bank"
}
curl --request PATCH \
--url https://api-sandbox.hokodo.co/v1/payment/orders/<order_id> \
--header "Content-Type: application/json" \
--header "Authorization: <your_api_key>" \
--data-binary '{
"status": "paid",
"paid_date": "2018-06-10",
"pay_method": "bank"
}'
Response
200 Ok
Content-Type: application/json
{
"url": "https://api-sandbox.hokodo.co/v1/payment/orders/order-yQKxbtCg9aTS5JYnsRVA9B",
"id": "order-yQKxbtCg9aTS5JYnsRVA9B",
"unique_id": "876987-987uinjojna-I8UH98Jnj",
"customer": {
"type": "registered",
"organisation": "org-ypTaHiLv5kgqSn4TzCr7xb",
"user": "user-nNqgg5AFymQMumaU7EdrLa",
"delivery_address": {
"name": "John Smith",
"address_line1": "1 Station Street",
"address_line2": "Flat B",
"address_line3": "",
"city": "London",
"region": "",
"postcode": "SE11 6NQ",
"country": "GB",
"phone": "",
"email": ""
}
},
"status": "paid",
"currency": "GBP",
"pay_method": "",
"total_amount": 12000,
"tax_amount": 2000,
"order_date": "2018-04-25",
"invoice_date": "2018-04-25",
"due_date": "2018-05-25",
"paid_date": "2018-06-10",
"pay_method": "bank",
"items": [],
"metadata": null,
"payment_offer": null,
"deferred_payment": null
}
Errors
errors | description |
---|---|
400 | a required field is missing or some of the fields have incorrect value |
409 | the order is already insured, modification is not allowed |
Delete order
Request
DELETE /v1/payment/orders/<order_id> HTTP/1.1
Authorization: Token <your_api_key>
curl --request DELETE \
--url https://api-sandbox.hokodo.co/v1/payment/orders/<order_id> \
--header "Authorization: <your_api_key>"
Responses
- regular response
204 No Content
- order not found
404 Not Found
Content-Type: application/json
{
"detail": "Not found."
}
- order can not be deleted
409 Conflict
Content-Type: application/json
Delete a previously created order.
Errors
errors | description |
---|---|
404 | the order_id is probably invalid, the order has not been found |
409 | the order can not be deleted |
Order Documents
OrderDocuments are documents such as an invoice, credit note, or a shipping document associated with a particular order.
Invoices
Invoices are normally sent by the merchant to the customer at the time of delivery. Hokodo need these invoices to support the collections process, because it is very common for customers to ask for the invoice to be re-sent to them before they make payment. Therefore, once the merchant generates the invoice, it must also be shared with Hokodo using this endpoint.
Credit Notes
Credit notes are sent by the merchant to the customer whenever a post-sale action such as a discount or return is applied to an order. If you issue credit notes when processing discounts or returns, you can save your operations team a significant amount of time by uploading the credit note to Hokodo using this endpoint at the time they are raised. This allows Hokodo to respond to the customer and resolve any queries without the need to liaise with your operations team.
Shipping documents
Shipping documents are documents associated with delivery, such as a copy of the delivery confirmation signed by the recipient. These documents are useful should there be any disputes about whether delivery occurred. If merchants are routinely capturing delivery confirmation documents, then systematically sharing these with Hokodo using this endpoint will save on operational hassle for Hokodo and the merchant if/when they are ever needed.
Other
Other can be used for any other documents that the merchant wishes to share with Hokodo
OrderDocument Object
{
"id": "odoc-afapG98cKaCL5VRjVfQQ2S",
"order": "order-yQKxbtCg9aTS5JYnsRVA9B",
"deferred_payment_event": "dpevnt-Lunu5hUgEnWyNYoaj3tPUc",
"doc_type": "invoice",
"description": "Invoice sent to customer",
"amount": 10000,
"metadata": {"unique_id": "some_unique_id",
"number": "some_invoice_number"},
"file": "https://hokodo-sandbox-clientdocuments.s3.amazonaws.com/media/order_documents/..."
}
field | type | description |
---|---|---|
id | string(uuid) | API unique identifier of the order document |
order | string(uuid) | API identifier of the linked order |
doc_type | string | Type of document, see below |
deferred_payment_event | string(uuid) | API identifier of a linked deferred payment event |
description | string | Description of the document |
amount | int | Value of the document in minor units (e.g. a credit note worth £100, will have amount=10000) |
metadata | dict | Set of key-value pairs you can attach to the object. You can use this to store your custom data in the object and read it back later. |
file | string(uri) | Link to the document hosted by Hokodo |
OrderDocument type
Possible order document types are:
invoice
credit_note
purchase_order
shipping
(shipping documents)other
Create OrderDocument
POST /v1/payment/orders/<order_id>/documents HTTP/1.1
Host: api-sandbox.hokodo.co
Content-Type: multipart/form-data; boundary=X-CLIENT-BOUNDARY
Authorization: Token <your_api_key>
Accept: */*
Content-Length: <total_lenth>
--X-CLIENT-BOUNDARY
Content-Disposition: form-data; name="doc_type"
invoice
--X-CLIENT-BOUNDARY
Content-Disposition: form-data; name="description"
<invoice_description>
--X-CLIENT-BOUNDARY
Content-Disposition: form-data; name="amount"
<invoice_amount>
--X-CLIENT-BOUNDARY
Content-Disposition: form-data; name="metadata"
Content-Type: application/json
<invoice_metadata>
--X-CLIENT-BOUNDARY
Content-Disposition: form-data; name="file"; filename="invoice.pdf"
Content-Type: application/pdf
<...actual binary content of the file...>
--X-CLIENT-BOUNDARY
curl --request POST \
--url https://api-sandbox.hokodo.co/v1/payment/orders/<order_id>/documents \
--header 'Authorization: Token <your_api_key>' \
--form doc_type=invoice \
--form deferred_payment_event=deferred_payment_event_id \
--form description=invoice_description \
--form amount=invoice_amount \
--form metadata=invoice_metadata \
--form file=@/local/path/to/file/invoice.pdf
To create an OrderDocument, you'll need to make a post request with the Content-Type set to multipart form data. In the request body please include the binary content from the file you wish to upload.
You can optionally include doc_type
, deferred_payment_event
, unique_ID
, description
, amount
, and metadata
.
field | type | flags | description |
---|---|---|---|
file | file | required | Content of the document |
doc_type | string | optional | Type of document, see above |
deferred_payment_event | string | optional | Linked Post Sale Action |
description | string | optional | Description of the document |
amount | int | optional | Value of the document in minor units (e.g. a credit note worth £100, will have amount=10000) |
metadata | dict | optional | Set of key-value pairs you can attach to the object. You can use this to store your custom data in the object and read it back later. |
Errors
errors | description |
---|---|
400 | a required field is missing |
View order document
Requests
GET /v1/payment/orders/<order_id>/documents/<document_id> HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/payment/orders/<order_id>/documents/<document_id> \
--header "Authorization: <your_api_key>"
Responses
200 Ok
Content-Type: application/json
{
"id": "odoc-afapG98cKaCL5VRjVfQQ2S",
"order": "order-yQKxbtCg9aTS5JYnsRVA9B",
"doc_type": "invoice",
"deferred_payment_event": "dpevnt-Lunu5hUgEnWyNYoaj3tPUc",
"description": "Invoice Description",
"amount": 10000,
"metadata": {"unique_id": "some_unique_id",
"number": "some_invoice_number"},
"file": "https://hokodo-sandbox-clientdocuments.s3.amazonaws.com/media/order_documents/..."
}
- order document not found
404 Not Found
Content-Type: application/json
{
"detail": "Not found."
}
Look up a previously created order document.
Errors
errors | description |
---|---|
404 | the order_document_id is probably invalid, the order document has not been found |
Payment Intents
A payment intent describes and order and an intent to purchase that order by means of a payment offer. The Intent combines both order and payment offer requests in to a single request, elements from order and payment offer are required.
Intent endpoints
POST v1/payment/intents
GET v1/payment/intents
GET v1/payment/intents/<intent_id>
Intent Object
{
"id": "intent-Y3UvYpizaQ7W4iCXe8cSLN",
"payment_url": "https://pay-local.hokodo.co/?intent=intent-Y3UvYpizaQ7W4iCXe8cSLN&key=oXVtSW01WsWf5n1UcI5EASIuNlri1Lbr-ulVPkaO51Q",
"order": "order-C2F5DSy3rnBEmk6BbZGmNb",
"created": "2024-03-13T07:26:07.676742Z",
"request": {
"company": {
"id": "co-bqRyKAGaFrEEN8JMjWJiqk",
# or
"country": "GB",
"reg_number": "10421422"
},
"order": {
"unique_id": "your-unique-order-id",
"customer": {
"user": {
"email": "bnpl.customer.paymentplan_offered.dp_fraud_accepted.2024-03-1317103147608200826@example.com",
"type": "registered",
"name": "John smith",
"phone": "0146384738",
"registered": "2023-07-01T12:12:12Z",
"unique_id": "user-1234"
},
"delivery_address": {
"name": "Autograph Homes",
"address_line1": "Unit 3 The Stables",
"address_line2": "Says Court Farm Badminton, Road, Frampton Cotterell",
"city": "Bristol",
"postcode": "BS36 2NY",
"country": "GB"
},
"invoice_address": {
"name": "Autograph Homes",
"address_line1": "Unit 3 The Stables",
"address_line2": "Says Court Farm Badminton, Road, Frampton Cotterell",
"city": "Bristol",
"postcode": "BS36 2NY",
"country": "GB"
}
},
"currency": "GBP",
"total_amount": 10000
},
"merchant_urls": {
"success": "https://merchant.com/payment/ok",
"cancel": "https://merchant.com/checkout",
"failure": "https://merchant.com/checkout",
"notification": "https://webhook.site/dev-hosted-checkout"
},
"locale": "en-gb"
}
}
field | type | description |
---|---|---|
id | string(uuid) | API unique identifier for the intent |
payment_url | string(url) | URL where to redirect the customer for payment |
order | string(uuid) or dictionary | Order object linked to Intent, can be expanded using ?expand=order |
request | dictionary | Content of the request used to create the Payment Intent (see below) |
Content of the request
field | type | description |
---|---|---|
order[currency] | currency | Currency of order amounts (ISO 4217 code) |
order[total_amount] | int | Total amount including tax, in minor units (cents) |
order[tax_amount] | int | Total amount of the taxes, in minor units (cents) |
order[customer] | dictionary | Customer making the order |
order[customer][user] | dictionary | https://bnpl.docs.hokodo.co/?http#user-object |
order[customer][organisation] | dictionary | Organisations |
order[customer][delivery_address] | dictionary | Delivery/shipping address for this order. See Addresses for a description of the fields |
order[customer][invoice_address] | dictionary | Invoice (or Billing) address for this order. See Addresses for a description of the fields |
order[items] | list | Optional list of items that constitute the order |
order[*] | All optional fields of an order can be passed and are still optionals | |
company | dictionary | Company search info about the buyer |
company[id] | string(uuid) | API company identifier if known |
company[country] | country | Country the company is registered in - not required if id is present |
company[reg_number] | string | Registration number in country - not required if id is present |
merchant_urls | dictionary | Redirection and callback URLs |
merchant_urls[success] | string(url) | URL to redirect the customer to if the deferred payment application is a success |
merchant_urls[failure] | string(url) | URL to redirect the customer to if the deferred payment application is rejected. For example the checkout page to finish with another payment method |
merchant_urls[cancel] | string(url) | URL to redirect the customer to if they cancel the application before completing it. For example the checkout page to finish with another payment method |
merchant_urls[notification] | string(url) | Callback URL to receive notifications about the deferred payment application |
locale | string | Language and region of the customer (RFC 1766), for example "en-gb" or "fr-fr” |
Requesting an Intent
Request
POST /v1/payment/intents HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
{
"company": {
"id": "co-bqRyKAGaFrEEN8JMjWJiqk",
# or
"country": "GB",
"reg_number": "10421422"
},
"merchant_urls": {
"success": "https://merchant.com/payment/ok",
"cancel": "https://merchant.com/checkout",
"failure": "https://merchant.com/checkout",
"notification": "https://webhook.site/dev-hosted-checkout"
},
"locale": "en-gb"
"order": {
"unique_id": "your-unique-order-id",
"currency": "GBP",
"total_amount": 10000,
"customer": {
"user": {
"email": "bnpl.customer.paymentplan_offered.dp_fraud_accepted.@example.com",
"type": "registered",
"name": "John smith",
"phone": "0146384738",
"registered": "2023-07-01T12:12:12Z",
"unique_id": "user-1234"
},
"delivery_address": {
"name": "Autograph Homes",
"address_line1": "Unit 3 The Stables",
"address_line2": "Says Court Farm Badminton, Road, Frampton Cotterell",
"city": "Bristol",
"postcode": "BS36 2NY",
"country": "GB"
},
"invoice_address": {
"name": "Autograph Homes",
"address_line1": "Unit 3 The Stables",
"address_line2": "Says Court Farm Badminton, Road, Frampton Cotterell",
"city": "Bristol",
"postcode": "BS36 2NY",
"country": "GB"
}
}
}
}
curl --request POST \
--url https://api-sandbox.hokodo.co/v1/payment/intents \
--header 'Content-Type: application/json' \
--header 'Authorization: Token <your_api_key>' \
--data-binary '{
"company": {
"id": "co-bqRyKAGaFrEEN8JMjWJiqk",
# or
"country": "GB",
"reg_number": "10421422"
},
"merchant_urls": {
"success": "https://merchant.com/payment/ok",
"cancel": "https://merchant.com/checkout",
"failure": "https://merchant.com/checkout",
"notification": "https://webhook.site/dev-hosted-checkout"
},
"locale": "en-gb"
"order": {
"unique_id": "your-unique-order-id",
"currency": "GBP",
"total_amount": 10000,
"customer": {
"user": {
"email": "bnpl.customer.paymentplan_offered.dp_fraud_accepted.@example.com",
"type": "registered",
"name": "John smith",
"phone": "0146384738",
"registered": "2023-07-01T12:12:12Z",
"unique_id": "user-1234"
},
"delivery_address": {
"name": "Autograph Homes",
"address_line1": "Unit 3 The Stables",
"address_line2": "Says Court Farm Badminton, Road, Frampton Cotterell",
"city": "Bristol",
"postcode": "BS36 2NY",
"country": "GB"
},
"invoice_address": {
"name": "Autograph Homes",
"address_line1": "Unit 3 The Stables",
"address_line2": "Says Court Farm Badminton, Road, Frampton Cotterell",
"city": "Bristol",
"postcode": "BS36 2NY",
"country": "GB"
}
}
}
}'
Response
{
"id": "intent-Y3UvYpizaQ7W4iCXe8cSLN",
"payment_url": "https://pay-local.hokodo.co/?intent=intent-Y3UvYpizaQ7W4iCXe8cSLN&key=oXVtSW01WsWf5n1UcI5EASIuNlri1Lbr-ulVPkaO51Q",
"order": "order-C2F5DSy3rnBEmk6BbZGmNb",
"created": "2024-03-13T07:26:07.676742Z",
"request": {
"company": {
"id": "co-bqRyKAGaFrEEN8JMjWJiqk",
# or
"country": "GB",
"reg_number": "10421422"
},
"order": {
"unique_id": "your-unique-order-id",
"customer": {
"user": {
"email": "bnpl.customer.paymentplan_offered.dp_fraud_accepted.2024-03-1317103147608200826@example.com",
"type": "registered",
"name": "John smith",
"phone": "0146384738",
"registered": "2023-07-01T12:12:12Z",
"unique_id": "user-1234"
},
"delivery_address": {
"name": "Autograph Homes",
"address_line1": "Unit 3 The Stables",
"address_line2": "Says Court Farm Badminton, Road, Frampton Cotterell",
"city": "Bristol",
"postcode": "BS36 2NY",
"country": "GB"
},
"invoice_address": {
"name": "Autograph Homes",
"address_line1": "Unit 3 The Stables",
"address_line2": "Says Court Farm Badminton, Road, Frampton Cotterell",
"city": "Bristol",
"postcode": "BS36 2NY",
"country": "GB"
}
},
"currency": "GBP",
"total_amount": 10000
},
"merchant_urls": {
"success": "https://merchant.com/payment/ok",
"cancel": "https://merchant.com/checkout",
"failure": "https://merchant.com/checkout",
"notification": "https://webhook.site/dev-hosted-checkout"
},
"locale": "en-gb"
}
}
Requesting an Intent
combines the following actions in to a single request:
The response will contain a payment_url
where the buyer can be redirected to checkout with Hokodo.
field | type | flags | description |
---|---|---|---|
order[currency] | currency | required | Currency of order amounts (ISO 4217 code) |
order[total_amount] | int | required | Total amount including tax, in minor units (cents) |
order[tax_amount] | int | optional | Total amount of the taxes, in minor units (cents) |
order[customer] | dictionary | required | Customer making the order |
order[customer][user] | dictionary | required | See fields required to create a user |
order[customer][organisation] | dictionary | optional | See fields required for Organisations |
order[customer][delivery_address] | dictionary | required | Delivery/shipping address for this order. See Addresses for a description of the fields |
order[customer][invoice_address] | dictionary | required | Invoice (or Billing) address for this order. See Addresses for a description of the fields |
order[items] | list | optional | Optional list of items that constitute the order |
order[*] | optional | All optional fields of an order can be passed and are still optionals | |
company | dictionary | optional | Company search info about the buyer |
company[id] | string(uuid) | optional | API company identifier if known |
company[country] | country | optional | Country the company is registered in - not required if id is present |
company[reg_number] | string | optional | Registration number in country - not required if id is present |
merchant_urls | dictionary | required | Redirection and callback URLs |
merchant_urls[success] | string(url) | required | URL to redirect the customer to if the deferred payment application is a success |
merchant_urls[failure] | string(url) | required | URL to redirect the customer to if the deferred payment application is rejected. For example the checkout page to finish with another payment method |
merchant_urls[cancel] | string(url) | required | URL to redirect the customer to if they cancel the application before completing it. For example the checkout page to finish with another payment method |
merchant_urls[notification] | string(url) | required | Callback URL to receive notifications about the deferred payment application |
locale | string | optional | Language and region of the customer (RFC 1766), for example "en-gb" or "fr-fr” |
Optional company field
The company
fields are optional. If you have already identified the company
of the buyer, you can provide it to speed up the process or avoid interaction
from the buyer. Otherwise, Hokodo's payment interface will take care of
collecting that information from the user themselves.
If you have the company
identifier, whether because you've used our company
search, or you have the registration number of the company of
the buyer, and you provide it in the payment intent, we will run a credit check
synchronously and you will be able to get the result immediately in the
response of your API call.
To make the best use of that, we recommend including
?expand=order.customer,order.payment_offer
as query parameter in your API
request, so you will have the full Order
expanded, including the Payment
Offer. You will then get this info in the response:
payment_url
: the main payment URL for the payment intent. You can use this whether or not you have expanded theOrder
order.payment_offer.offered_payment_plans[*].status
: for each of the payment plans configured, whether it's offered or declined (see payment plan status)order.payment_offer.offered_payment_plans[*].payment_url
: for each of the payment plans configured, its specific payment URL, pre-selecting that payment plan
Payment Offers
The Offer API is used to create a set of payment plans for your customer. Simply provide an order id and Hokodo will return a list of payment plans that you can share with your customer at checkout, or over email or text message.
Offer Endpoints
POST /v1/payment/offers
GET /v1/payment/offers/<offer_id>
GET /v1/payment/offers
DELETE /v1/payment/offers/<offer_id>
PUT /v1/payment/payment_plans/<plan_id>/send_offer_email
Offer Object
{
"url": "https://api-sandbox.hokodo.co/v1/payment/offers/offer-bqRyHAGaFrDEN8JNjXJirp",
"id": "offer-bqRyHAGaFrDEN8JNjXJirp",
"order": "order-dTHo9Q2idffT7CMPCVjztA",
"offered_payment_plans": [
{
"id": "ppln-bqRyHAGaFrDEN8JNjXJirp",
"name": "net30",
"template": "pptemp-RySHMoFqSxfmkcfrYC2VeF",
"currency": "GBP",
"protected_amount": 100000,
"unprotected_amount": 0,
"scheduled_payments": [
{
"date": "2020-10-16",
"amount": 100000,
"discounted_amount": 100000,
"customer_fee": {
"percentage": "0.00",
"amount": 0
},
"allowed_payment_methods": [
{"type": "card", "providers": ["card_provider_name"]},
{"type": "direct_debit", "providers": ["dd_provider_name"]},
{"type": "bank_transfer", "providers": ["bt_provider_name"]}
],
"payment_method": {
"type": "card",
"card": {
"brand": "mastercard",
"exp_month": 4,
"exp_year": 2044,
"last4": "1375"
}
},
"due_date_config": {
"due_after_nb_days": 30,
"due_end_of_nb_months": null,
"amount_percentage": "100.0",
"is_upfront_payment": false
}
}
],
"payment_terms_relative_to": "order_creation",
"merchant_fee": {
"currency": "GBP",
"amount": 1000
},
"customer_fee": {
"currency": "GBP",
"percentage": "0.00",
"amount": 0
},
"customer_percentage_discount": "0.00",
"customer_discount": {
"currency": "GBP",
"amount": 0
},
"valid_until": "2020-09-16T12:44:49.841Z",
"payment_url": "https://payment.app.hokodo.co/plans/ppln-bqRyHAGaFrDEN8JNjXJirp",
"status": "offered",
"rejection_reason": null,
"has_upfront_payment": false,
"credit_actions": []
},
{
"id": "ppln-3NeZcmAw3rpQPN788mxKJi",
"name": "90d + upfront",
"template": "pptemp-LAMds7L6ENQ2BCwxQykHKE",
"currency": "GBP",
"protected_amount": 100000,
"unprotected_amount": 0,
"scheduled_payments": [
{
"date": "2020-09-16",
"amount": 25000,
"discounted_amount": 25000,
"customer_fee": {
"percentage": "0.00",
"amount": 0
},
"allowed_payment_methods": [
{"type": "card", "providers": ["card_provider_name"]}
],
"payment_method": {
"type": "card",
"card": {
"brand": "mastercard",
"exp_month": 4,
"exp_year": 2044,
"last4": "1375"
}
},
"due_date_config": {
"due_after_nb_days": null,
"due_end_of_nb_months": null,
"amount_percentage": "25.0",
"is_upfront_payment": true
}
},
{
"date": "2020-12-16",
"amount": 75000,
"discounted_amount": 75000,
"customer_fee": {
"percentage": "0.00",
"amount": 0
},
"allowed_payment_methods": [
{"type": "card", "providers": ["card_provider_name"]},
{"type": "direct_debit", "providers": ["dd_provider_name"]}
],
"payment_method": {
"type": "card",
"card": {
"brand": "mastercard",
"exp_month": 4,
"exp_year": 2044,
"last4": "1375"
}
},
"due_date_config": {
"due_after_nb_days": 30,
"due_end_of_nb_months": null,
"amount_percentage": "75.0",
"is_upfront_payment": false
}
}
],
"payment_terms_relative_to": "order_creation",
"merchant_fee": {
"currency": "GBP",
"amount": 1000
},
"customer_fee": {
"currency": "GBP",
"percentage": "0.00",
"amount": 0
},
"customer_percentage_discount": "0.00",
"customer_discount": {
"currency": "GBP",
"amount": 0
},
"valid_until": "2020-09-16T12:44:49.841Z",
"payment_url": "https://payment.app.hokodo.co/plans/ppln-3NeZcmAw3rpQPN788mxKJi",
"status": "offered",
"rejection_reason": null,
"has_upfront_payment": true,
"credit_actions": []
}
],
"urls": {
"success": "https://merchant.com/payment/ok",
"failure": "https://merchant.com/checkout",
"cancel": "https://merchant.com/checkout",
"notification": "https://backend.merchant.com/payment/notifications",
"merchant_terms": "https://merchant.com/terms"
},
"locale": "en-gb",
"metadata": {}
}
field | type | description |
---|---|---|
url | string | API endpoint to access the Offer |
id | string(uuid) | API identifier for the Offer |
order | string(uuid) | API identifier for the attached Transaction |
offered_payment_plans | list | List of payment plans you can offer to your customer |
legals | dictionary | An internal field which is subject to change |
urls | dictionary | Redirection and callback URLs |
urls[merchant_terms] | string(url) | URL for the terms and conditions of your platform, to display to the user |
urls[success] | string(url) | URL to redirect the customer to if the deferred payment application is a success |
urls[failure] | string(url) | URL to redirect the customer to if the deferred payment application is rejected. For example the checkout page to finish with another payment method |
urls[cancel] | string(url) | URL to redirect the customer to if they cancel the application before completing it. For example the checkout page to finish with another payment method |
urls[notification] | string(url) | Callback URL to receive notifications about the deferred payment application |
locale | string | Language and region of the customer (RFC 1766), for example "en-gb" or "fr-fr" |
metadata | dictionary | Set of key-value pairs to store additional information about the Offer |
Payment Plan Object
field | type | description |
---|---|---|
id | string(uuid) | API identifier for the Payment Plan |
name | string | Payment plan name (e.g. Pay in 30 days, Pay in 3 installments) |
template | string | Hokodo identifier of the template from which the payment plan data object was created |
currency | string | ISO 4217 currency code (e.g. GBP , EUR ) |
protected_amount | int | Amount that can be protected by Hokodo, in minor units (cents) |
unprotected_amount | int | Amount without insurance against non-payment, in minor units (cents) |
scheduled_payments | list | The re-payment schedule for the plan (e.g. your customer will pay £x amount on YYYY-MM-DD date) |
scheduled_payments[date] | string | Date when the payment is due (e.g. 2020-09-16 ). If you offer your buyers payment terms upon fulfillment/capture (e.g. payment_terms_relative_to=first_capture ), when order fulfillment/capture occurs, then this date may be recalculated and updated |
scheduled_payments[amount] | int | Amount your customer will pay on this date in pence/cents |
scheduled_payments[discounted_amount] | int | Projected amount in draft mode, amount including discount, in pence/cents, your customer will pay once this scheduled payment is no longer in draft |
scheduled_payments[customer_fee] | dictionary | Amount, in pence/cents, and percentage of the fees for the customer for this scheduled payment (included in the scheduled payment amount) |
scheduled_payments[allowed_payment_methods] | list | List of payment method types allowed to make a payment with available providers |
scheduled_payments[payment_method] | dictionary | Payment method assigned to use. This gets assigned when the Deferred Payment is created (null if there is no DeferredPayment) |
scheduled_payments[due_date_config] | dictionary | A Scheduled Payment Due Date Config object. The settings that determine how your buyers scheduled_payments will be generated |
payment_terms_relative_to | string | An event in the lifecycle of an order. Your buyers scheduled payment dates will be calculated relative to the date of this event. Either order_creation , when your buyer is checking-out. Or first_capture , when you mark any part of the order as fulfilled/captured |
merchant_fee | dictionary | Amount and currency of the fees for you for this payment plan |
customer_fee | dictionary | Amount, percentage, and currency of the fees for the customer for this payment plan (included in the scheduled payments) |
customer_percentage_discount | string | Percentage to discount on the order for this payment plan |
customer_discount | dictionary | Amount and currency of the discount for the customer for this payment plan |
valid_until | date | Time when payment plan offer expires. After this date, your customer cannot avail of this plan |
payment_url | string | Link where your customer can apply for the payment plan |
status | string | Current status of the payment plan (e.g. offered , accepted , declined , expired , cancelled ) |
rejection_reason | dictionary | Rejection reason if Offer is declined, see rejection reasons |
rejection_reason[code] | string | A text label identifying the reason |
rejection_reason[detail] | string | A detailed explanation of why the Offer was declined. This can be shared with your customer |
rejection_reason[params] | dictionary | A dictionary of dynamic key-value pairs which can be used to customize the rejection reason |
credit_actions | list | Possible actions that can affect the decision positively |
credit_actions[code] | string | A text label identifying the action |
credit_actions[description_display] | string | description with params substituted in |
credit_actions[description] | string | A detailed explanation of the action a buyer should take when submitting a credit limit request |
credit_actions[params] | dictionary | Pairs of values that should be substituted in to description |
has_upfront_payment | boolean | If this template contain a scheduled payment to be paid upfront, False otherwise |
protected_amount
and unprotected_amount
can be used to check what part of a
payment plan will be protected by Hokodo or not. If your contract permits it,
payment offers can be created that are not totally protected by Hokodo.
Note: When your customer clicks on the Payment plan's payment_url
a Deferred Payment object
will be created automatically.
Payment Method Object
field | type | description |
---|---|---|
type | string | Type of the payment method. Currently: card , direct_debit , bank_transfer |
card | dict (optional) | |
direct_debit | dict (optional) |
Payment Method Object: Card
field | type | description |
---|---|---|
brand | string | Brand of the bank card. Currently: amex , mastercard , visa |
exp_month | string | Expiry month |
exp_year | string | Expiry year |
last4 | string | Last 4 digits of the card number |
Payment Method Object: Direct Debit
field | type | description |
---|---|---|
account_holder_name | string | Name of the account holder |
account_number_ending | string | Last 2 digits of the account number |
bank_name | string | Bank name |
country | string | Country of the account |
currency | string | Payment currency |
scheme | string | Bank payment scheme. Currently: bacs , sepa_core |
Scheduled Payment Due Date Config Object
field | type | description |
---|---|---|
due_after_nb_days | int | A rule for deciding how the scheduled_payments.date will be calculated. It will be relative to the event specified in the payment plan payment_terms_relative_to . This will be null if due_end_of_nb_months has been specified instead |
due_end_of_nb_months | int | A rule for deciding how the scheduled_payments.date will be calculated. The payment will be due on the last day of a month. The month it will be due on, is the current month, plus the value of this field. This is relative to the event specified in the payment plan payment_terms_relative_to . A value of 0 means it will be due at the end of the current month. 1 means at the end of next month. This will be null if due_end_of_nb_days has been specified instead |
amount_percentage | decimal | The amount your buyer will pay at this time, as a percentage of the total order value. This value may be null for old/historical payment offers. |
is_upfront_payment | boolean | Is True if this scheduled payment should be paid upfront |
Request a New Offer
Request
POST /v1/payment/offers HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
{
"order": "order-dTHo9Q2idffT7CMPCVjztA",
"urls": {
"success": "https://merchant.com/payment/ok",
"failure": "https://merchant.com/checkout",
"cancel": "https://merchant.com/checkout",
"notification": "https://backend.merchant.com/payment/notifications",
"merchant_terms": "https://merchant.com/terms"
},
"locale": "en-gb",
"metadata": {}
}
curl --request POST \
--url https://api-sandbox.hokodo.co/v1/payment/offers \
--header "Content-Type: application/json" \
--header "Authorization: <your_api_key>" \
--data-binary '{
"order": "order-dTHo9Q2idffT7CMPCVjztA",
"urls": {
"success": "https://merchant.com/payment/ok",
"failure": "https://merchant.com/checkout",
"cancel": "https://merchant.com/checkout",
"notification": "https://backend.merchant.com/payment/notifications",
"merchant_terms": "https://merchant.com/terms"
},
"locale": "en-gb",
"metadata": {}
}'
Responses
- Offer Offered
201 Created
Content-Type: application/json
{
"url": "https://api-sandbox.hokodo.co/v1/payment/offers/offer-EzH6BixNSHvaByEpXcFW5h",
"id": "offer-bqRyHAGaFrDEN8JNjXJirp",
"order": "order-dTHo9Q2idffT7CMPCVjztA",
"offered_payment_plans": [
{
"id": "ppln-gJdDHAGaFrDLDvJNXJird",
"name": "4xEOM",
"template": "pptemp-RySHMoFqSxfmkcfrYC2VeF",
"currency": "GBP",
"protected_amount": 100400,
"unprotected_amount": 0,
"scheduled_payments": [
{
"date": "2020-09-30",
"amount": 25100,
"discounted_amount": 25100,
"customer_fee": {
"percentage": "0.00",
"amount": 0
},
"allowed_payment_methods": [
{"type": "card", "providers": ["card_provider_name"]},
{"type": "direct_debit", "providers": ["dd_provider_name"]},
{"type": "bank_transfer", "providers": ["bt_provider_name"]}
],
"payment_method": null,
"due_date_config": {
"due_after_nb_days": null,
"due_end_of_nb_months": 0,
"amount_percentage": "25.0",
"is_upfront_payment": false
}
},
{
"date": "2020-10-31",
"amount": 25100,
"discounted_amount": 25100,
"customer_fee": {
"percentage": "0.00",
"amount": 0
},
"allowed_payment_methods": [
{"type": "card", "providers": ["card_provider_name"]}
],
"payment_method": null,
"due_date_config": {
"due_after_nb_days": null,
"due_end_of_nb_months": 1,
"amount_percentage": "25.0",
"is_upfront_payment": false
}
},
{
"date": "2020-11-30",
"amount": 25100,
"discounted_amount": 25100,
"customer_fee": {
"percentage": "0.00",
"amount": 0
},
"allowed_payment_methods": [
{"type": "card", "providers": ["card_provider_name"]}
],
"payment_method": null,
"due_date_config": {
"due_after_nb_days": null,
"due_end_of_nb_months": 2,
"amount_percentage": "25.0",
"is_upfront_payment": false
}
},
{
"date": "2020-12-31",
"amount": 25100,
"discounted_amount": 25100,
"customer_fee": {
"percentage": "0.00",
"amount": 0
},
"allowed_payment_methods": [
{"type": "card", "providers": ["card_provider_name"]}
],
"payment_method": null,
"due_date_config": {
"due_after_nb_days": null,
"due_end_of_nb_months": 3,
"amount_percentage": "25.0",
"is_upfront_payment": false
}
}
],
"payment_terms_relative_to": "order_creation",
"merchant_fee": {
"currency": "GBP",
"amount": 1000
},
"customer_fee": {
"currency": "GBP",
"percentage": "0.00",
"amount": 0
},
"customer_percentage_discount": "0.00",
"customer_discount": {
"currency": "GBP",
"amount": 0
},
"valid_until": "2020-09-16T12:44:49.841Z",
"payment_url": "https://payment.app.hokodo.co/plans/ppln-bqRyHAGaFrDEN8JNjXJirp",
"status": "offered",
"rejection_reason": null,
"has_upfront_payment": false,
"credit_actions": []
}
],
"urls": {
"success": "https://merchant.com/payment/ok",
"failure": "https://merchant.com/checkout",
"cancel": "https://merchant.com/checkout",
"notification": "https://backend.merchant.com/payment/notifications",
"merchant_terms": "https://merchant.com/terms"
},
"locale": "en-gb",
"metadata": {}
}
- Offer Rejected
201 Created
Content-Type: application/json
{
"url": "https://api-sandbox.hokodo.co/v1/payment/offers/offer-3VezfMFGKX6U247jRhXAkQ",
"id": "offer-3VezfMFGKX6U247jRhXAkQ",
"order": "order-yQKxbtCg9aTS5JYnsRVA9B",
"offered_payment_plans": [
{
"id": "ppln-bqRyHAGaFrDEN8JNjXJirp",
"name": "net30",
"template": "pptemp-RySHMoFqSxfmkcfrYC2VeF",
"currency": "GBP",
"protected_amount": 100000,
"unprotected_amount": 0,
"scheduled_payments": [
{
"date": "2020-10-16",
"amount": 100000,
"discounted_amount": 100000,
"customer_fee": {
"percentage": "0.00",
"amount": 0
},
"allowed_payment_methods": [
{"type": "card", "providers": ["card_provider_name"]},
{"type": "direct_debit", "providers": ["dd_provider_name"]},
{"type": "bank_transfer", "providers": ["bt_provider_name"]}
],
"payment_method": {
"type": "card",
"card": {
"brand": "mastercard",
"exp_month": 4,
"exp_year": 2044,
"last4": "1375"
}
},
"due_date_config": {
"due_after_nb_days": 30,
"due_end_of_nb_months": null,
"amount_percentage": "100.0",
"is_upfront_payment": false
}
}
],
"payment_terms_relative_to": "order_creation",
"merchant_fee": {
"currency": "GBP",
"amount": 1000
},
"customer_fee": {
"currency": "GBP",
"percentage": "0.00",
"amount": 0
},
"customer_percentage_discount": "0.00",
"customer_discount": {
"currency": "EUR",
"amount": 0
},
"valid_until": "2020-09-16T12:44:49.841Z",
"payment_url": "https://payment.app.hokodo.co/plans/ppln-bqRyHAGaFrDEN8JNjXJirp",
"status": "declined",
"rejection_reason": {
"code": "buyer-country",
"detail": "We're currently unable to provide payment plans to Buyers domiciled in {debtor_country}.",
"params": {
"debtor_country": "Ireland"
}
},
"has_upfront_payment": false,
"credit_actions": [
{
"code": "company-financials",
"description": "Please submit {months} bank statements",
"params": {"months": 4},
"description_display": "Please submit 4 months of bank statements"
}
]
}
],
"urls": {
"success": "https://merchant.com/payment/ok",
"failure": "https://merchant.com/checkout",
"cancel": "https://merchant.com/checkout",
"notification": "https://backend.merchant.com/payment/notifications",
"merchant_terms": "https://merchant.com/terms"
},
"locale": "en-gb",
"metadata": {}
}
This endpoint is used to create a list of payment options for your customer. The required fields are
- the API identifier of the
Order
, - URLs to redirect the customer once the payment is successful, rejected or cancelled by the customer.
You can optionally include a metadata
object to store additional information about the Offer.
field | type | flags | description |
---|---|---|---|
order | string(uuid) | required | API unique identifier of the order |
urls | dictionary | required | Redirection and callback URLs |
urls[merchant_terms] | string(url) | required | URL for the terms and conditions of your platform, to display to the user |
urls[success] | string(url) | required | URL to redirect the customer to if the deferred payment application is a success |
urls[failure] | string(url) | required | URL to redirect the customer to if the deferred payment application is rejected. For example the checkout page to finish with another payment method |
urls[cancel] | string(url) | required | URL to redirect the customer to if they cancel the application before completing it. For example the checkout page to finish with another payment method |
urls[notification] | string(url) | required | Callback URL to receive notifications about the deferred payment application |
locale | string | optional | Language and region of the customer (RFC 1766), for example "en-gb" or "fr-fr" |
metadata | dictionary | optional | Set of key-value pairs to store additional information about the Offer. |
Errors
errors | description |
---|---|
400 | a required field is missing |
409 | can't obtain an offer as order has already been paid |
List Offers
Request
GET /v1/payment/offers HTTP/1.1
Authorization: Token <your_api_key>
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/payment/offers \
--header "Authorization: <your_api_key>"
Response
200 Ok
Content-Type: application/json
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"url": "https://api-sandbox.hokodo.co/v1/payment/offers/offer-EzH6BixNSHvaByEpXcFW5h",
"id": "offer-bqRyHAGaFrDEN8JNjXJirp",
"order": "order-dTHo9Q2idffT7CMPCVjztA",
"offered_payment_plans": [
{
"id": "ppln-bqRyHAGaFrDEN8JNjXJirp",
"name": "net30",
"template": "pptemp-RySHMoFqSxfmkcfrYC2VeF",
"currency": "GBP",
"protected_amount": 100000,
"unprotected_amount": 0,
"scheduled_payments": [
{
"date": "2020-10-16",
"amount": 100000,
"discounted_amount": 100000,
"customer_fee": {
"percentage": "0.00",
"amount": 0
},
"allowed_payment_methods": [
{"type": "card", "providers": ["card_provider_name"]},
{"type": "direct_debit", "providers": ["dd_provider_name"]},
{"type": "bank_transfer", "providers": ["bt_provider_name"]}
],
"payment_method": {
"type": "card",
"card": {
"brand": "mastercard",
"exp_month": 4,
"exp_year": 2044,
"last4": "1375"
}
},
"due_date_config": {
"due_after_nb_days": 30,
"due_end_of_nb_months": null,
"amount_percentage": "100.0",
"is_upfront_payment": false
}
}
],
"payment_terms_relative_to": "order_creation",
"merchant_fee": {
"currency": "GBP",
"amount": 1000
},
"customer_fee": {
"currency": "GBP",
"percentage": "0.00",
"amount": 0
},
"customer_percentage_discount": "0.00",
"customer_discount": {
"currency": "EUR",
"amount": 0
},
"valid_until": "2020-09-16T12:44:49.841Z",
"payment_url": "https://payment.app.hokodo.co/plans/ppln-bqRyHAGaFrDEN8JNjXJirp",
"status": "offered",
"rejection_reason": null,
"has_upfront_payment": false,
"credit_actions": []
}
],
"urls": {
"success": "https://merchant.com/payment/ok",
"failure": "https://merchant.com/checkout",
"cancel": "https://merchant.com/checkout",
"notification": "https://backend.merchant.com/payment/notifications",
"merchant_terms": "https://merchant.com/terms"
},
"locale": "en-gb",
"metadata": {}
},
{
"url": "https://api-sandbox.hokodo.co/v1/payment/offers/offer-3VezfMFGKX6U247jRhXAkQ",
"id": "offer-3VezfMFGKX6U247jRhXAkQ",
"order": "order-yQKxbtCg9aTS5JYnsRVA9B",
"offered_payment_plans": [
{
"id": "ppln-bqRyHAGaFrDEN8JNjXJirp",
"name": "net30",
"template": "pptemp-gXPguT3zqDQamD5N3KEjp2",
"currency": "GBP",
"protected_amount": 100000,
"unprotected_amount": 0,
"scheduled_payments": [
{
"date": "2020-10-16",
"amount": 100000,
"discounted_amount": 100000,
"customer_fee": {
"percentage": "0.00",
"amount": 0
},
"allowed_payment_methods": [
{"type": "card", "providers": ["card_provider_name"]},
{"type": "direct_debit", "providers": ["dd_provider_name"]},
{"type": "bank_transfer", "providers": ["bt_provider_name"]}
],
"payment_method": {
"type": "card",
"card": {
"brand": "mastercard",
"exp_month": 4,
"exp_year": 2044,
"last4": "1375"
}
},
"due_date_config": {
"due_after_nb_days": 30,
"due_end_of_nb_months": null,
"amount_percentage": "100.0",
"is_upfront_payment": false
}
}
],
"payment_terms_relative_to": "order_creation",
"merchant_fee": {
"currency": "GBP",
"amount": 1000
},
"customer_fee": {
"currency": "GBP",
"percentage": "0.00",
"amount": 0
},
"customer_percentage_discount": "0.00",
"customer_discount": {
"currency": "EUR",
"amount": 0
},
"valid_until": "2020-09-16T12:44:49.841Z",
"payment_url": "https://payment.app.hokodo.co/plans/ppln-bqRyHAGaFrDEN8JNjXJirp",
"status": "declined",
"rejection_reason": {
"code": "buyer-country",
"detail": "We're currently unable to provide payment plans to Buyers domiciled in {debtor_country}.",
"params": {
"debtor_country": "Ireland"
}
},
"has_upfront_payment": false,
"credit_actions": []
}
],
"urls": {
"success": "https://merchant.com/payment/ok",
"failure": "https://merchant.com/checkout",
"cancel": "https://merchant.com/checkout",
"notification": "https://backend.merchant.com/payment/notifications",
"merchant_terms": "https://merchant.com/terms"
},
"locale": "en-gb",
"metadata": {}
}
]
}
List all previously requested Offers
View Offer
Request
GET /v1/payment/offers/<offer_id> HTTP/1.1
Authorization: Token <your_api_key>
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/payment/offers/<offer_id> \
--header "Authorization: <your_api_key>"
Responses
- regular response
200 Ok
Content-Type: application/json
{
"url": "https://api-sandbox.hokodo.co/v1/payment/offers/offer-EzH6BixNSHvaByEpXcFW5h",
"id": "offer-bqRyHAGaFrDEN8JNjXJirp",
"order": "order-dTHo9Q2idffT7CMPCVjztA",
"offered_payment_plans": [
{
"id": "ppln-bqRyHAGaFrDEN8JNjXJirp",
"name": "net30",
"template": "pptemp-RySHMoFqSxfmkcfrYC2VeF",
"currency": "GBP",
"protected_amount": 100000,
"unprotected_amount": 0,
"scheduled_payments": [
{
"date": "2020-10-16",
"amount": 100000,
"discounted_amount": 100000,
"customer_fee": {
"percentage": "0.00",
"amount": 0
},
"allowed_payment_methods": [
{"type": "card", "providers": ["card_provider_name"]},
{"type": "direct_debit", "providers": ["dd_provider_name"]},
{"type": "bank_transfer", "providers": ["bt_provider_name"]}
],
"payment_method": {
"type": "card",
"card": {
"brand": "mastercard",
"exp_month": 4,
"exp_year": 2044,
"last4": "1375"
}
},
"due_date_config": {
"due_after_nb_days": 30,
"due_end_of_nb_months": null,
"amount_percentage": "100.0",
"is_upfront_payment": false
}
}
],
"payment_terms_relative_to": "order_creation",
"merchant_fee": {
"currency": "GBP",
"amount": 1000
},
"customer_fee": {
"currency": "GBP",
"percentage": "0.00",
"amount": 0
},
"customer_percentage_discount": "0.00",
"customer_discount": {
"currency": "EUR",
"amount": 0
},
"valid_until": "2020-09-16T12:44:49.841Z",
"payment_url": "https://payment.app.hokodo.co/plans/ppln-bqRyHAGaFrDEN8JNjXJirp",
"status": "offered",
"rejection_reason": null,
"has_upfront_payment": false,
"credit_actions": []
}
],
"urls": {
"success": "https://merchant.com/payment/ok",
"failure": "https://merchant.com/checkout",
"cancel": "https://merchant.com/checkout",
"notification": "https://backend.merchant.com/payment/notifications",
"merchant_terms": "https://merchant.com/terms"
},
"locale": "en-gb",
"metadata": {}
}
- Not Found
404 Not Found
Content-Type: application/json
{
"detail": "Not found."
}
Retrieve a Previously Requested Offer
Errors
Errors | Description |
---|---|
404 | The Offer id is probably incorrect, a Offer has not been found |
Delete Offer
Request
DELETE /v1/payment/offers/<offer_id> HTTP/1.1
Authorization: Token <your_api_key>
curl --request DELETE \
--url https://api-sandbox.hokodo.co/v1/payment/offers/<offer_id> \
--header "Authorization: <your_api_key>"
Responses
- regular response
204 No Content
- Not Found
404 Not Found
Content-Type: application/json
{
"detail": "Not found."
}
- Unable to Delete Accepted Offer
409 Conflict
Content-Type: application/json
Delete a Previously Requested Offer
Errors
errors | description |
---|---|
404 | The Offer id is probably incorrect, a Offer has not been found |
409 | Can't delete the Offer, probably because it's already been accepted |
Mail offer to customer
Request
PUT /v1/payment/payment_plans/ppln-bqRyHAGaFrDEN8JNjXJirp/send_offer_email HTTP/1.1
Authorization: Token <your_api_key>
curl --request PUT \
--url https://api-sandbox.hokodo.co/v1/payment/payment_plans/ppln-bqRyHAGaFrDEN8JNjXJirp/send_offer_email \
--header "Authorization: <your_api_key>"
Responses
- Offer sent to customer by email
200 OK
Content-Type: application/json
{
"detail": "Payment plan email sent."
}
You can use this endpoint to have Hokodo send an email to the customer, with a link to a specific payment plan.
Errors
errors | description |
---|---|
400 | Payment Plan invalid (for example declined) |
Deferred Payments
A Deferred Payment object is created when your customer completes the process to pay with Hokodo.
Deferred Payment Endpoints
GET /v1/payment/deferred_payments/<deferredpayment_id>
Deferred Payment Object
{
"url": "https://api-sandbox.hokodo.co/v1/payment/deferred_payments/defpay-bqRyGIGaORKiK8bhMVPirp",
"id": "defpay-bqRyGIGaORKiK8bhMVPirp",
"number": "P-7WR2-PR0S",
"created": "2022-07-11T12:48:02.788770Z",
"payment_plan": "ppln-gJdDHAGaFrDLDvJNXJird",
"order": "order-dTHo9Q2idffT7CMPCVjztA",
"rejection_reason":
{
"code": "insufficient_funds",
"detail": "Insufficient funds"
},
"status": "pending_review",
"repayment_info": null,
"currency": "GBP",
"authorisation": 50000,
"protected_captures": 0,
"unprotected_captures": 0,
"refunds": 10000,
"voided_authorisation": 15000,
"expired_authorisation": 0,
"clawback_amount": 0,
"events": []
}
field | type | description |
---|---|---|
url | string | API endpoint to access the Deferred Payment |
id | string(uuid) | API unique identifier for the Deferred Payment |
number | string | The Deferred Payment's customer friendly public identifier (e.g. "P-7WR2-PR0S") |
created | datetime | Date & Time the Deferred Payment was created |
payment_plan | string(uuid) | API unique identifier of the personalised payment plan attached to the deferred payment |
order | string(uuid) | API identifier for the Order |
rejection_reason | dictionary | Rejection reason, null if not rejected |
rejection_reason[code] | string | A text label identifying the reason |
rejection_reason[detail] | string | An explanation of why the deferred payment was rejected |
status | string | Deferred Payment status |
repayment_info[status] | string | Repayment status |
repayment_info[amount] | int | Total amount buyer has to pay for order, in minor units (cents) |
repayment_info[paid_amount] | int | Amount buyer has already paid for order, in minor units (cents) |
repayment_info[outstanding_amount] | int | Outstanding amount that buyer will have to pay, in minor units (cents). Note: this outstanding amount may not be due yet |
repayment_info[currency] | currency | Currency of deferred payment amounts |
repayment_info[scheduled_payments] | list | List of payments we expect the buyer to make (see Repayment Info) |
currency | currency (ISO 4217 code) | Currency of deferred payment amounts |
authorisation | int | Amount that can still be captured and protected by Hokodo, in minor units (cents) |
protected_captures | int | Amount that will be asked from the buyer with insurance against non-payment, in minor units (cents) |
unprotected_captures | int | Amount that will be asked from the buyer without insurance against non-payment, in minor units (cents) |
refunds | int | Amount that the buyer might have been asked to pay at some point but is not due anymore, in minor units (cents) |
voided_authorisation | int | Amount that used to be authorised but has been released by API, in minor units (cents) |
expired_authorisation | int | Amount that used to be authorised but has been automatically released, in minor units (cents) |
clawback_amount | int | Amount that has been clawed back to Hokodo due to buyer non-payment in unprotected credit/fraud contexts, in minor units (cents) |
events[*] | Post Sale event | List of events created by post-sale actions (see below for details) |
Values of all amounts above from authorisation
to expired_authorisation
are guaranteed to sum to a constant amount,
equal to the order total amount. See next section about post-sale actions for more details on how
these amounts can change.
The amount that has been captured (and not refunded or clawed back) is split between protected_captures
and unprotected_captures
.
All captures will be protected_captures
up to the protected_amount
of the Payment Plan.
For details on the difference between these two types of capture, see Protected Captures vs. Unprotected Captures.
Deferred Payment status
When it is created, the deferred payment status
can be one of:
code | description |
---|---|
accepted | the payment has been accepted |
pending_review | the payment is pending manual review by Hokodo, you will be notified of the result |
customer_action_required | more information is required by the customer (e.g. upload KYC documents) |
rejected | the payment has been rejected by Hokodo |
After that, dependent upon the post sale API version in use, the deferred payment status
can become one of:
code | description | post sale version |
---|---|---|
part_fulfilled | the payment has been partially fulfilled, and there is more to be fulfilled | v1 |
fulfilled | the payment has been fulfilled (partially or all), and there is nothing left to fulfil | v1 |
reversed | the payment might have been fulfilled, but everything has been returned and there is nothing left to fulfil | v1 |
cancelled | no fulfilment has been attempted, the payment has been entirely cancelled | v1 |
part_captured | the payment has been partially captured, and there is some authorisation remaining | v2 |
captured | the payment has been captured (partially or fully), and there is no authorisation remaining | v2 |
refunded | the payment might have been captured, but everything has been refunded and there is no authorisation left | v2 |
voided | no capture has been attempted, the payment has been entirely voided | v2 |
expired | the payment has expired before anything had been captured | v2 |
Rejection reason
Provides information on the reason for rejection.
{
"rejection_reason":
{
"code": "insufficient_funds",
"detail": "Insufficient funds"
},
"status": "rejected"
}
Possible reasons for rejection:
- The offer was declined
- The payment authorisation with the given card payment method was declined, for various reasons. For example (non-exhaustive):
- insufficient_funds
- payment_declined
- card_error
Repayment info
Provides information on the repayments.
field | type | description |
---|---|---|
status | string | Repayment status |
amount | int | Total amount buyer has to pay for order, in minor units (cents) |
paid_amount | int | Amount buyer has already paid for order, in minor units (cents) |
outstanding_amount | int | Outstanding amount that buyer will have to pay, in minor units (cents). Note: this outstanding amount may not be due yet |
currency | currency | Currency of deferred payment amounts |
scheduled_payments | list | List of scheduled payments we expect the buyer to make |
scheduled_payments[status] | string | Repayment status for this individual payment |
scheduled_payments[due_date] | date | Date we expect the buyer to make payment on |
scheduled_payments[overdue_date] | date | Date we will block the buyer from future credit if payment has not been received |
scheduled_payments[amount] | int | Amount we expect the buyer to pay by the due_date |
scheduled_payments[paid_amount] | list | Amount the buyer has paid towards this payment |
scheduled_payments[outstanding_amount] | list | Amount the buyer still has to pay for this payment to become paid |
Repayment status
code | description |
---|---|
not_due_yet | The buyer has not paid yet, but their next scheduled payment is in the future |
due | The buyer has not yet paid their expected payment. But credit is not yet blocked. |
overdue | The buyer has still not paid and it is past the credit buffer window. We will block this buyer from receiving credit on new transactions |
paid | The deferred payment has been fully paid by the buyer |
cancelled | The deferred payment has been fully refunded or voided, so the buyer has nothing to pay |
Note: Hokodo provide a buffer window for receiving payments, meaning the buyer will not be blocked until status
becomes overdue
. overdue_date
can be used to find when that will happen.
The right hand column has example data for installment plans. The first example having an unpaid installment, the 2nd example being fully paid.
{
"repayment_info": {
"status": "due",
"amount": 120,
"paid_amount": 20,
"outstanding_amount": 100,
"currency": "GBP",
"scheduled_payments": [{"status": "paid", "due_date": "2024-01-01", "overdue_date": "2024-01-11", "amount": 20, "paid_amount": 20, "outstanding_amount": 0}, {"status": "due", "due_date": "2024-02-01", "overdue_date": "2024-02-11", "amount": 100, "paid_amount": 0, "outstanding_amount": 100}]
}
}
{
"repayment_info": {
"status": "paid",
"amount": 100,
"paid_amount": 100,
"outstanding_amount": 0,
"currency": "GBP",
"scheduled_payments": [{"status": "paid", "due_date": "2024-01-01", "overdue_date": "2024-01-11", "amount": 100, "paid_amount": 100, "outstanding_amount": 0}]
}
}
View Deferred Payment
Request
GET /v1/payment/deferred_payments/<deferredpayment_id> HTTP/1.1
Authorization: Token <your_api_key>
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/payment/deferred_payments/<deferredpayment_id> \
--header "Authorization: <your_api_key>"
Responses
- regular response
200 Ok
Content-Type: application/json
{
"url": "https://api-sandbox.hokodo.co/v1/payment/deferred_payments/defpay-bqRyGIGaORKiK8bhMVPirp",
"id": "defpay-bqRyGIGaORKiK8bhMVPirp",
"number": "P-7WR2-PR0S",
"payment_plan": "ppln-gJdDHAGaFrDLDvJNXJird",
"order": "order-dTHo9Q2idffT7CMPCVjztA",
"status": "accepted",
"repayment_info": null,
"currency": "GBP",
"authorisation": 50000,
"protected_captures": 20000,
"unprotected_captures": 0,
"refunds": 10000,
"voided_authorisation": 15000,
"expired_authorisation": 5000,
"clawback_amount": 0
}
- Not Found
404 Not Found
Content-Type: application/json
{
"detail": "Not found."
}
Retrieve an existing Deferred Payment object.
Post Sale actions
After the deferred payment has been created, you must use the post-sale endpoints to inform Hokodo about order completion (usually shipment) and other events happening after the sale process.
In terms of API objects: to complete the checkout, the buyer accepts a PaymentOffer
and a DeferredPayment
is
created. The post-sale endpoints relate to that particular DeferredPayment
, and make modifications to notify Hokodo
of how much of the Order
the buyer should be charged for.
- capture: Let Hokodo know that some value of goods have been shipped or provided. This triggers Hokodo to charge captured amounts to Buyers according to their chosen PaymentPlan and pay you according to the agreed payout schedule.
- refund: Some value of shipped goods has been returned to you or you wish to apply a discount on the value of goods shipped.
- void: If part, or all, of the remaining authorisation should be released. Voids happen automatically in the form of expiry after a period determined in your contract, but if you wish to free up authorisation immediately (because you know goods will not be shipped, and you wish to free up Buyers' credit limit for further BNPL orders) you can use this endpoint. Voiding authorisation you don't plan on using is thus optional but heavily recommended.
These will not all be necessary for every order. The base flow would be:
- Create the
Order
. - Request the
PaymentOffer
. - The customer accepts one of the payment plans and confirms the order.
- You ask us to capture an amount from the customer equal to the value of goods shipped.
- Hokodo generates a payout to you according to schedule.
- Hokodo records that customer shall repay that amount later, based upon the customer's payment plan.
Post sale endpoints
POST /v1/payment/deferred_payments/<deferred_payment_id>/capture
POST /v1/payment/deferred_payments/<deferred_payment_id>/capture_remaining
POST /v1/payment/deferred_payments/<deferred_payment_id>/refund
POST /v1/payment/deferred_payments/<deferred_payment_id>/void
POST /v1/payment/deferred_payments/<deferred_payment_id>/void_remaining
Post sale event
{
"id": "dpevnt-Lunu5hUgEnWyNYoaj3tPUc",
"created": "2020-10-15T19:53:42.345Z",
"type": "capture",
"amount": 5000,
"currency": "GBP",
"metadata": {
"reference": "Bob's burger patties",
"supplier": "Krusty Krabs Factory"
},
"changes": {
"authorisation": -5000,
"protected_captures": 5000,
"unprotected_captures": 0,
"refunds": 0,
"voided_authorisation": 0,
"expired_authorisation": 0,
"clawback": 0,
"customer_fee": {
"authorisation": 0,
"captures": 0,
"refunds": 0,
"voided_authorisation": 0,
"expired_authorisation": 0
}
}
}
field | type | flags | description |
---|---|---|---|
id | string(uuid) | read-only | API unique identifier for the Post Sale Event |
created | datetime | read-only | Date & Time the Post Sale Event was created |
type | string | read-only | Type of the event (e.g. capture , refund , void , expiry , adjustment ) |
amount | int | required | Amount of money moved as part of the event, in minor units (cents) |
currency | currency (ISO 4217 code) | read-only | Currency of all monetary amounts recorded by this event |
metadata | dictionary | optional | Set of key-value pairs to store additional information about the event. This information is copied into the PayoutItem.deferred_payment_event_metadata for payout responses |
changes[authorisation] | int | read-only | Change in the Deferred Payment 's authorisation caused by this event, in minor units (cents) |
changes[protected_captures] | int | read-only | Change in the Deferred Payment 's protected_captures caused by this event, in minor units (cents) |
changes[unprotected_captures] | int | read-only | Change in the Deferred Payment 's unprotected_captures caused by this event, in minor units (cents) |
changes[refunds] | int | read-only | Change in the Deferred Payment 's refunds caused by this event, in minor units (cents) |
changes[voided_authorisation] | int | read-only | Change in the Deferred Payment 's voided_authorisation caused by this event, in minor units (cents) |
changes[clawback] | int | read-only | Change in the Deferred Payment 's clawback caused by this Hokodo-initiated clawback event, in minor units (cents) |
changes[expired_authorisation] | int | read-only | Change in the Deferred Payment 's expired_authorisation caused by this event, in minor units (cents) |
changes[customer_fee] | dictionary | read-only | Contains changes affecting the customer fee post sale values, caused by this event, in minor units (cents) |
Each event is to be interpreted as an accounting entry moving money from an account to another. Because of that following conditions are guaranteed:
- The sum of all
changes
is equal to zero. - The sum of all positive
changes
is equal toamount
(and thus positive).
Events of type expiry
are equivalent to void
events but are created automatically by Hokodo after some time
define in your contract. This exists to ensure that authorisation is eventually freed for your customer to continue
using Hokodo's BNPL solution.
Events of type adjustment
might be created by Hokodo operations to help you tidy up bookkeeping in case of mistakes or
to handle corner cases. These should however be rare to best enjoy the power of the API.
You may want to notify Hokodo that a specific event relates to an individual supplier or is related to a specific item.
You might also want to record the tracking number of the shipment. The metadata
field can be used to record any of
this information for future use. Data in this metadata
field can be included in the payout information we send to you
to ease reconciliation.
Post Sale API supports idempotent requests, detailed in the section on Idempotent requests.
Capture
Request
POST /v1/payment/deferred_payments/defpay-bqRyGIGaORKiK8bhMVPirp/capture HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
Idempotency-Key: 33871f6b-ff2f-4de3-9e10-ff42ef7af553
{
"amount": 100000,
"metadata": {
"reference": "Bobs burger patties"
}
}
curl --request POST \
--url https://api-sandbox.hokodo.co/v1/payment/deferred_payments/defpay-bqRyGIGaORKiK8bhMVPirp/capture \
--header "Content-Type: application/json" \
--header "Authorization: <your_api_key>" \
--header "Idempotency-Key: 33871f6b-ff2f-4de3-9e10-ff42ef7af553" \
--data-binary '{
"amount": 100000,
"metadata": {
"reference": "Bobs burger patties"
}
}'
Response
201 Ok
Content-Type: application/json
{
"id": "dpevnt-Lunu5hUgEnWyNYoaj3tPUc",
"created": "2020-10-15T19:53:42.345Z",
"type": "capture",
"amount": 100000,
"currency": "GBP",
"metadata": {
"reference": "Bobs burger patties"
},
"changes": {
"authorisation": -100000,
"protected_captures": 100000,
"unprotected_captures": 0,
"refunds": 0,
"voided_authorisation": 0,
"expired_authorisation": 0,
"clawback": 0,
"customer_fee": {
"authorisation": 0,
"captures": 0,
"refunds": 0,
"voided_authorisation": 0,
"expired_authorisation": 0
}
}
}
Notifies Hokodo that goods have been shipped or services provided to the customer. The given amount
of money is now
due by the customer on top of what had already been captured before. Money is moved from authorisation
to
protected_captures
first and possibly unprotected_captures
.
It is important to notify Hokodo when the order is shipped because this is the trigger for Hokodo to make a payment to you and is the value that we will charge the customer according to the agreed payment plan. This endpoint is usually called when the package has been handed over to the carrier or the customer given access to services. Make sure that your fulfilment department, or external fulfilment partner, has access to the API. If the order is sent out by multiple shipments, you should make a request for each shipment.
Protected Captures vs. Unprotected Captures
The amount that has been captured (and not refunded) is split between the protected_captures
and unprotected_captures
fields.
All captures will be protected_captures
up to the protected_amount
of the Payment Plan. There are two ways to get unprotected_captures
:
- If you have the Merchant Limits feature enabled, you may have an
unprotected_amount
on your Payment Plan. In this case, any captures above theprotected_amount
will appear asunprotected_captures
. The Deferred Payment'sauthorisation
includes both the protected and unprotected part. - If you have the Overcaptures feature enabled, any captures above the Deferred Payment's
authorisation
will be taken asunprotected_captures
. The Deferred Payment'sauthorisation
will become negative.
Constraints
Capture data must contain an amount
and can include metadata
.
The value of amount
should be the cost of the goods that have been captured at this time, including any tax or
shipment fee:
amount
should be positiveamount
shouldn't be greater than the deferred paymentauthorisation
, unless allowed within certain limits by your contract (see discussion above aboutunprotected_captures
)
You will receive an HTTP error 400 in case these conditions aren't met.
Capture all the remaining authorisation
Request
POST /v1/payment/deferred_payments/defpay-bqRyGIGaORKiK8bhMVPirp/capture_remaining HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
Idempotency-Key: 33871f6b-ff2f-4de3-9e10-ff42ef7af553 \
{
"metadata": {
"reference": "Bobs burger patties"
}
}
curl --request POST \
--url https://api-sandbox.hokodo.co/v1/payment/deferred_payments/defpay-bqRyGIGaORKiK8bhMVPirp/capture_remaining \
--header "Content-Type: application/json" \
--header "Authorization: <your_api_key>" \
--header "Idempotency-Key: 33871f6b-ff2f-4de3-9e10-ff42ef7af553" \
--data-binary '{
"metadata": {
"reference": "Bobs burger patties"
}
}'
Responses
- authorisation > 0
201 Ok
Content-Type: application/json
{
"id": "dpevnt-Lunu5hUgEnWyNYoaj3tPUc",
"created": "2020-10-15T19:53:42.345Z",
"type": "capture",
"amount": 100000,
"currency": "GBP",
"metadata": {
"reference": "Bobs burger patties"
},
"changes": {
"authorisation": -100000,
"protected_captures": 100000,
"unprotected_captures": 0,
"refunds": 0,
"voided_authorisation": 0,
"expired_authorisation": 0,
"clawback": 0,
"customer_fee": {
"authorisation": 0,
"captures": 0,
"refunds": 0,
"voided_authorisation": 0,
"expired_authorisation": 0
}
}
}
- authorisation == 0
200 Ok No content
Capture all the remaining authorisation
. This behaves differently based on the remaining authorisation
:
- If the remaining
authorisation
> 0 then the endpoint will capture all the remainingauthorisation
. - If the remaining
authorisation
== 0 then the endpoint will do nothing.
Refund
Request
POST /v1/payment/deferred_payments/defpay-bqRyGIGaORKiK8bhMVPirp/refund HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
Idempotency-Key: 33871f6b-ff2f-4de3-9e10-ff42ef7af553
{
"amount": 30000,
"metadata": {
"reference": "Bobs burger patties"
}
}
curl --request POST \
--url https://api-sandbox.hokodo.co/v1/payment/deferred_payments/defpay-bqRyGIGaORKiK8bhMVPirp/refund \
--header "Content-Type: application/json" \
--header "Authorization: <your_api_key>" \
--header "Idempotency-Key: 33871f6b-ff2f-4de3-9e10-ff42ef7af553" \
--data-binary '{
"amount": 30000,
"metadata": {
"reference": "Bobs burger patties"
}
}'
Response
201 Ok
Content-Type: application/json
{
"id": "dpevnt-Lunu5hUgEnWyNYoaj3tPUc",
"created": "2020-10-15T19:53:42.345Z",
"type": "refund",
"amount": 30000,
"currency": "GBP",
"metadata": {
"reference": "Bobs burger patties"
},
"changes": {
"authorisation": 0,
"protected_captures": -30000,
"unprotected_captures": 0,
"refunds": 30000,
"voided_authorisation": 0,
"expired_authorisation": 0,
"clawback": 0,
"customer_fee": {
"authorisation": 0,
"captures": 0,
"refunds": 0,
"voided_authorisation": 0,
"expired_authorisation": 0
}
}
}
Notifies Hokodo that a customer has been refunded goods or services or and that we should charge less than previously told.
You should use this endpoint when a customer returns goods or you want to reduce the captured amount
for any other
reason (like applying an immediate discount as a gesture of good will). A refund can be any value up to the amount
that has been previously captured using v1/payment/deferred_payment/<deferred_payment_id>/capture
.
Note that any amount previously captured above the authorisation
and counted toward unprotected_captures
is refunded
first so that as much as possible of the amount due buy the buyer is insured against non-payment.
Constraints
Refund data must contain an amount
and can include metadata
.
The value of amount
should be how much you wish to refund to the customer:
amount
should be positiveamount
must not be greater than theDeferredPayment.protected_captures + DeferredPayment.unprotected_captures
.
Void
Request
POST /v1/payment/deferred_payments/defpay-bqRyGIGaORKiK8bhMVPirp/void HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
Idempotency-Key: 33871f6b-ff2f-4de3-9e10-ff42ef7af553
{
"amount": 5000,
"metadata": {
"reference": "Bobs burger patties"
}
}
curl --request POST \
--url https://api-sandbox.hokodo.co/v1/payment/deferred_payments/defpay-bqRyGIGaORKiK8bhMVPirp/void \
--header "Content-Type: application/json" \
--header "Authorization: <your_api_key>" \
--header "Idempotency-Key: 33871f6b-ff2f-4de3-9e10-ff42ef7af553" \
--data-binary '{
"amount": 5000,
"metadata": {
"reference": "Bobs burger patties"
}
}'
Response
201 Ok
Content-Type: application/json
{
"id": "dpevnt-Lunu5hUgEnWyNYoaj3tPUc",
"created": "2020-10-15T19:53:42.345Z",
"type": "void",
"amount": 5000,
"currency": "GBP",
"metadata": {
"reference": "Bobs burger patties"
},
"changes": {
"authorisation": -5000,
"protected_captures": 0,
"unprotected_captures": 0,
"refunds": 0,
"voided_authorisation": 5000,
"expired_authorisation": 0,
"clawback": 0,
"customer_fee": {
"authorisation": 0,
"captures": 0,
"refunds": 0,
"voided_authorisation": 0,
"expired_authorisation": 0
}
}
}
Notifies Hokodo that a part of the order has been cancelled and you don't intend on capturing some of the initial authorisation. The purpose of this is to release part or all of the buyers remaining authorisation with Hokodo and thus increase their credit limit.
Constraints
Void data must contain an amount
and can include metadata
.
The value of amount
should be how much you wish to cancel from the order and not charge the customer:
amount
should be positiveamount
should be less than the deferred paymentauthorisation
You will receive an HTTP error 400 in case these conditions aren't met.
Void all the remaining authorisation
Request
POST /v1/payment/deferred_payments/defpay-bqRyGIGaORKiK8bhMVPirp/void_remaining HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
Idempotency-Key: 33871f6b-ff2f-4de3-9e10-ff42ef7af553
{
"metadata": {
"reference": "Bobs burger patties"
}
}
curl --request POST \
--url https://api-sandbox.hokodo.co/v1/payment/deferred_payments/defpay-bqRyGIGaORKiK8bhMVPirp/void_remaining \
--header "Content-Type: application/json" \
--header "Authorization: <your_api_key>" \
--header "Idempotency-Key: 33871f6b-ff2f-4de3-9e10-ff42ef7af553" \
--data-binary '{
"metadata": {
"reference": "Bobs burger patties"
}
}'
Responses
- authorisation > 0
201 Ok
Content-Type: application/json
{
"id": "dpevnt-Lunu5hUgEnWyNYoaj3tPUc",
"created": "2020-10-15T19:53:42.345Z",
"type": "void",
"amount": 100000,
"currency": "GBP",
"metadata": {
"reference": "Bobs burger patties"
},
"changes": {
"authorisation": -100000,
"protected_captures": 0,
"unprotected_captures": 0,
"refunds": 0,
"voided_authorisation": 100000,
"expired_authorisation": 0,
"clawback": 0,
"customer_fee": {
"authorisation": 0,
"captures": 0,
"refunds": 0,
"voided_authorisation": 0,
"expired_authorisation": 0
}
}
}
- authorisation == 0
200 Ok No content
Void all the remaining authorisation
. This behaves differently based on the remaining authorisation
:
- If the remaining
authorisation
> 0 then the endpoint will void all the remainingauthorisation
. - If the remaining
authorisation
== 0 then the endpoint will do nothing.
Post-sale Order actions (Legacy)
After a PaymentOffer has been accepted by the customer, you will need to use the following endpoints to make modifications to the Order.
- mark fulfilled: to let Hokodo know the order (or part of the order) has been shipped, and trigger payment from Hokodo to you,
- cancel: if the order (or part of the order) has been cancelled,
- return: if the customer has returned the order (or part of the order) after shipping,
- discount: if you grant a refund or discount to the customer.
These will not all be necessary for every order. The base flow would be:
- Create the Order.
- Request the PaymentOffer.
- The customer accepts one of the payment plans and confirms the order.
- You mark the order as fulfilled as you ship it.
- Hokodo sends you the money immediately.
- The customer pays Hokodo later.
Post-sale Order endpoints
PUT /v1/payment/orders/<order_id>/fulfill
PUT /v1/payment/orders/<order_id>/cancel
PUT /v1/payment/orders/<order_id>/return
PUT /v1/payment/orders/<order_id>/discount
PUT /v1/payment/orders/<order_id>/mark_disputed
Fulfillment
Request
PUT /v1/payment/orders/<order_id>/fulfill HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
{
"items": [
{
"item_id": "1",
"quantity": "10.000",
"total_amount": 10000,
"tax_amount": 2000,
"shipping_id": "DX49581904385",
"shipping_provider": "Postal service"
},
{
"item_id": "2",
"quantity": "1.000",
"total_amount": 2000,
"tax_amount": 400,
"shipping_id": "DX49581904385",
"shipping_provider": "Postal service"
}
]
}
curl --request PATCH \
--url https://api-sandbox.hokodo.co/v1/payment/orders/<order_id>/fulfill \
--header "Content-Type: application/json" \
--header "Authorization: <your_api_key>" \
--data-binary '{
"items": [
{
"item_id": "1",
"quantity": "10.000",
"total_amount": 10000,
"tax_amount": 1667,
"shipping_id": "DX49581904385",
"shipping_provider": "Postal service"
},
{
"item_id": "2",
"quantity": "1.000",
"total_amount": 2000,
"tax_amount": 333,
"shipping_id": "DX49581904385",
"shipping_provider": "Postal service"
}
]
}'
Response
200 Ok
Content-Type: application/json
{
"url": "https://api-sandbox.hokodo.co/v1/payment/orders/order-yQKxbtCg9aTS5JYnsRVA9B",
"id": "order-yQKxbtCg9aTS5JYnsRVA9B",
"unique_id": "876987-987uinjojna-I8UH98Jnj",
"customer": {
"type": "registered",
"organisation": "org-ypTaHiLv5kgqSn4TzCr7xb",
"user": "user-nNqgg5AFymQMumaU7EdrLa",
"delivery_address": {
"name": "John Smith",
"address_line1": "1 Station Street",
"address_line2": "Flat B",
"address_line3": "",
"city": "London",
"region": "",
"postcode": "SE11 6NQ",
"country": "GB",
"phone": "",
"email": ""
}
},
"status": "pending",
"currency": "GBP",
"pay_method": "",
"total_amount": 12000,
"tax_amount": 2000,
"order_date": "2018-04-25",
"invoice_date": "2018-04-25",
"due_date": "2018-06-25",
"paid_date": null,
"items": [
{
"item_id": "1",
"type": "product",
"description": "Super ergonomic chair",
"metadata": {"color": "black", "name": "Karmus", "variant": "M"},
"reference": "702.611.50",
"category": "Furniture > Chairs",
"supplier_id": "7363",
"supplier_name": "",
"quantity": "10.000",
"unit_price": 1000,
"tax_rate": "20.00",
"total_amount": 10000,
"tax_amount": 2000,
"fulfilled_quantity": 10,
"fulfillment_info": [
{
"quantity": "10.000",
"total_amount": 10000,
"tax_amount": 2000,
"shipping_id": "DX49581904385",
"shipping_provider": "Postal service",
"shipping_date": "2018-04-26"
}
],
"cancelled_quantity": 0,
"cancelled_info": null,
"returned_quantity": 0,
"returned_info": null
},
{
"item_id": "2",
"type": "shipping",
"description": "Delivery fee",
"metadata": {},
"reference": "",
"category": "",
"supplier_id": "",
"supplier_name": "",
"quantity": "1.000",
"unit_price": 2000,
"tax_rate": "20.00",
"total_amount": 2000,
"tax_amount": 400,
"fulfilled_quantity": 1,
"fulfillment_info": [
{
"quantity": "1.000",
"total_amount": 2000,
"tax_amount": 400,
"shipping_id": "DX49581904385",
"shipping_provider": "Postal service",
"shipping_date": "2018-04-26"
}
],
"cancelled_quantity": 0,
"cancelled_info": null,
"returned_quantity": 0,
"returned_info": null
}
],
"metadata": {
"customer_id": "2055b445-3d95-4d2f-bd80-3e336217905f",
"checkout_id": "c0185e68-89aa-42d5-93e9-476d01d4c97f"
},
"payment_offer": "offer-cqfxJVUwXBrkyZHRQaknJS",
"deferred_payment": "defpay-7PiKMX2gEpJmasb8Du65zn"
}
Fulfillment refers to the process of shipping the goods to the customer, or providing them with the service they have purchased. It is important that you notify Hokodo when fulfillment occurs since this is the trigger for our payment to you. This endpoint is usually called when the package has been handed over to the logistics carrier. Hint: Make sure that your fulfillment department (or external partner) has access to the API. Often, this requires some planning ahead.
Fulfillment information must include date and all items that have actually been delivered to the customer in the format similar to the list of items in the Order.
You can either ship the full order or only parts of the order. In case you initially only ship parts of the order:
- You have to send us further delivery confirmations until the entire order has been shipped (or cancelled).
- You always send the line items you have shipped with the original line number/id. For example, if you ship item 1 and item 4 of a 4 item basket, you send us lines 1+4 (and don’t change those numbers).
- You fill the fields "total_amount" and "tax_amount" with the sum of the items you shipped, not the original order total sum.
field | type | flags | description |
---|---|---|---|
items | list | required | The list of items that got shipped, each with the fields described below |
item_id | string | required | Your identifier for this line of the order, e.g. 1, 2, 3... |
quantity | decimal | required | Number of items shipped |
total_amount | int | required | Total amount including tax of the items that shipped, in minor units (cents) |
tax_amount | int | required | Total amount of the taxes of the items that shipped, in minor units (cents) |
shipping_id | string | optional | Tracking id of the shipping provider |
shipping_provider | string | optional | Name of the shipping provider |
Errors
errors | description |
---|---|
404 | the order_id is probably invalid, the order has not been found |
400 | a required field is missing or some of the fields have incorrect value |
Cancellation
Request
- partial cancellation of half the items in the Order
PUT /v1/payment/orders/<order_id>/cancel HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
{
"items": [
{
"item_id": "2",
"quantity": "1",
"total_amount": 2000,
"tax_amount": 400
}
]
}
curl --request PATCH \
--url https://api-sandbox.hokodo.co/v1/payment/orders/<order_id>/cancel \
--header "Content-Type: application/json" \
--header "Authorization: <your_api_key>" \
--data-binary '{
"items": [
{
"item_id": "2",
"quantity": "1",
"total_amount": 2000,
"tax_amount": 400
}
]
}'
Response
200 Ok
Content-Type: application/json
{
"url": "https://api-sandbox.hokodo.co/v1/payment/orders/order-yQKxbtCg9aTS5JYnsRVA9B",
"id": "order-yQKxbtCg9aTS5JYnsRVA9B",
"unique_id": "876987-987uinjojna-I8UH98Jnj",
"customer": {
"type": "registered",
"organisation": "org-ypTaHiLv5kgqSn4TzCr7xb",
"user": "user-nNqgg5AFymQMumaU7EdrLa",
"delivery_address": {
"name": "John Smith",
"address_line1": "1 Station Street",
"address_line2": "Flat B",
"address_line3": "",
"city": "London",
"region": "",
"postcode": "SE11 6NQ",
"country": "GB",
"phone": "",
"email": ""
}
},
"status": "pending",
"currency": "GBP",
"pay_method": "",
"total_amount": 7000,
"tax_amount": 1166,
"order_date": "2018-04-25",
"invoice_date": "2018-04-25",
"due_date": "2018-06-25",
"paid_date": null,
"items": [
{
"item_id": "1",
"type": "product",
"description": "Super ergonomic chair",
"metadata": {"color": "black", "name": "Karmus", "variant": "M"},
"reference": "702.611.50",
"category": "Furniture > Chairs",
"supplier_id": "7363",
"supplier_name": "",
"quantity": "5.000",
"unit_price": 1000,
"tax_rate": "20.00",
"total_amount": 5000,
"tax_amount": 1000,
"fulfilled_quantity": 0,
"fulfillment_info": null,
"cancelled_quantity": 0,
"cancelled_info": null,
"returned_quantity": 0,
"returned_info": null
},
{
"item_id": "2",
"type": "shipping",
"description": "Delivery fee",
"metadata": {},
"reference": "",
"category": "",
"supplier_id": "",
"supplier_name": "",
"quantity": "1.000",
"unit_price": 2000,
"tax_rate": "20.00",
"total_amount": 2000,
"tax_amount": 400,
"fulfilled_quantity": 0,
"fulfillment_info": null,
"cancelled_quantity": 1,
"cancelled_info": [
{
"quantity": "1.000",
"total_amount": 2000,
"tax_amount": 400
}
],
"returned_quantity": 0,
"returned_info": null
}
],
"metadata": {
"customer_id": "2055b445-3d95-4d2f-bd80-3e336217905f",
"checkout_id": "c0185e68-89aa-42d5-93e9-476d01d4c97f"
},
"payment_offer": "offer-cqfxJVUwXBrkyZHRQaknJS",
"deferred_payment": "defpay-7PiKMX2gEpJmasb8Du65zn"
}
If an order or individual items from an order are being cancelled by the customer before shipping, you need to notify us of the cancellation.
You can either cancel the full order or only parts of the order. In case you only cancel parts of the order:
- You always send the line items you cancel with the original line number. For example, if you cancel item "2" of a 4 item order, you send us line "2" (and don’t change this number).
- You fill the fields "total_amount" with the sum of the items you cancelled, not the original order total sum.
Returns
Request
- partial return of half the items in the Order
PUT /v1/payment/orders/<order_id>/return HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
{
"items": [
{
"item_id": "2",
"quantity": "1",
"total_amount": 2000,
"tax_amount": 400
}
]
}
curl --request PATCH \
--url https://api-sandbox.hokodo.co/v1/payment/orders/<order_id>/return \
--header "Content-Type: application/json" \
--header "Authorization: <your_api_key>" \
--data-binary '{
"items": [
{
"item_id": "2",
"quantity": "1",
"total_amount": 2000,
"tax_amount": 400
}
]
}'
Response
200 Ok
Content-Type: application/json
{
"url": "https://api-sandbox.hokodo.co/v1/payment/orders/order-yQKxbtCg9aTS5JYnsRVA9B",
"id": "order-yQKxbtCg9aTS5JYnsRVA9B",
"unique_id": "876987-987uinjojna-I8UH98Jnj",
"customer": {
"type": "registered",
"organisation": "org-ypTaHiLv5kgqSn4TzCr7xb",
"user": "user-nNqgg5AFymQMumaU7EdrLa",
"delivery_address": {
"name": "John Smith",
"address_line1": "1 Station Street",
"address_line2": "Flat B",
"address_line3": "",
"city": "London",
"region": "",
"postcode": "SE11 6NQ",
"country": "GB",
"phone": "",
"email": ""
}
},
"status": "pending",
"currency": "GBP",
"pay_method": "",
"total_amount": 7000,
"tax_amount": 1166,
"order_date": "2018-04-25",
"invoice_date": "2018-04-25",
"due_date": "2018-06-25",
"paid_date": null,
"items": [
{
"item_id": "1",
"type": "product",
"description": "Super ergonomic chair",
"metadata": {"color": "black", "name": "Karmus", "variant": "M"},
"reference": "702.611.50",
"category": "Furniture > Chairs",
"supplier_id": "7363",
"supplier_name": "",
"quantity": "5.000",
"unit_price": 1000,
"tax_rate": "20.00",
"total_amount": 5000,
"tax_amount": 1000,
"fulfilled_quantity": 5,
"fulfillment_info": [
{
"quantity": "5.000",
"total_amount": 5000,
"tax_amount": 1000,
"shipping_id": "DX49581904385",
"shipping_provider": "Postal service",
"shipping_date": "2018-04-26"
}
],
"cancelled_quantity": 0,
"cancelled_info": null,
"returned_quantity": 0,
"returned_info": null
},
{
"item_id": "2",
"type": "shipping",
"description": "Delivery fee",
"metadata": {},
"reference": "",
"category": "",
"supplier_id": "",
"supplier_name": "",
"quantity": "1.000",
"unit_price": 2000,
"tax_rate": "20.00",
"total_amount": 2000,
"tax_amount": 400,
"fulfilled_quantity": 1,
"fulfillment_info": [
{
"quantity": "1.000",
"total_amount": 2000,
"tax_amount": 400,
"shipping_id": "DX49581904385",
"shipping_provider": "Postal service",
"shipping_date": "2018-04-26"
}
],
"cancelled_quantity": 0,
"cancelled_info": null,
"returned_quantity": 1,
"returned_info": [
{
"quantity": "1.000",
"total_amount": 2000,
"tax_amount": 400
}
]
}
],
"metadata": {
"customer_id": "2055b445-3d95-4d2f-bd80-3e336217905f",
"checkout_id": "c0185e68-89aa-42d5-93e9-476d01d4c97f"
},
"payment_offer": "offer-cqfxJVUwXBrkyZHRQaknJS",
"deferred_payment": "defpay-7PiKMX2gEpJmasb8Du65zn"
}
If a shipped order (or individual items from an order) are being returned by the customer after shipping, you need to notify us of the return.
You can either return the full order or only parts of the order. In case you only return parts of the order:
- You always send the line items you return with the original line number. For example, if you return item "3" of a 4 item order, you send us line "3" (and don’t change this number).
- You fill the fields "total_amount" with the sum of the items you returned, not the original order total sum.
Refunds / discounts
Request
PUT /v1/payment/orders/<order_id>/discount HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
{
"items": [
{
"item_id": "99",
"description": "Discount following our email conversation",
"quantity": "1.000",
"unit_price": -120,
"tax_rate": "20.00",
"total_amount": -120,
"tax_amount": -20
}
]
}
curl --request PATCH \
--url https://api-sandbox.hokodo.co/v1/payment/orders/<order_id>/discount \
--header "Content-Type: application/json" \
--header "Authorization: <your_api_key>" \
--data-binary '{
"items": [
{
"item_id": "99",
"description": "Discount following our email conversation",
"quantity": "1.000",
"unit_price": -120,
"tax_rate": "20.00",
"total_amount": -120,
"tax_amount": -20
}
]
}'
Response
200 Ok
Content-Type: application/json
{
"url": "https://api-sandbox.hokodo.co/v1/payment/orders/order-yQKxbtCg9aTS5JYnsRVA9B",
"id": "order-yQKxbtCg9aTS5JYnsRVA9B",
"unique_id": "876987-987uinjojna-I8UH98Jnj",
"customer": {
"type": "registered",
"organisation": "org-ypTaHiLv5kgqSn4TzCr7xb",
"user": "user-nNqgg5AFymQMumaU7EdrLa",
"delivery_address": {
"name": "John Smith",
"address_line1": "1 Station Street",
"address_line2": "Flat B",
"address_line3": "",
"city": "London",
"region": "",
"postcode": "SE11 6NQ",
"country": "GB",
"phone": "",
"email": ""
}
},
"status": "pending",
"currency": "GBP",
"pay_method": "",
"total_amount": 11880,
"tax_amount": 1980,
"order_date": "2018-04-25",
"invoice_date": "2018-04-25",
"due_date": "2018-06-25",
"paid_date": null,
"items": [
{
"item_id": "1",
"type": "product",
"description": "Super ergonomic chair",
"metadata": {"color": "black", "name": "Karmus", "variant": "M"},
"reference": "702.611.50",
"category": "Furniture > Chairs",
"supplier_id": "7363",
"supplier_name": "",
"quantity": "10.000",
"unit_price": 1000,
"tax_rate": "20.00",
"total_amount": 10000,
"tax_amount": 2000,
"fulfillment_info": [
{
"quantity": "10.000",
"total_amount": 10000,
"tax_amount": 2000,
"shipping_id": "DX49581904385",
"shipping_provider": "Postal service",
"shipping_date": "2018-04-26"
}
]
},
{
"item_id": "2",
"type": "shipping",
"description": "Delivery fee",
"metadata": {},
"reference": "",
"category": "",
"supplier_id": "",
"supplier_name": "",
"quantity": "1.000",
"unit_price": 2000,
"tax_rate": "20.00",
"total_amount": 2000,
"tax_amount": 400,
"fulfilled_quantity": 1,
"fulfillment_info": [
{
"quantity": "1.000",
"total_amount": 2000,
"tax_amount": 400,
"shipping_id": "DX49581904385",
"shipping_provider": "Postal service",
"shipping_date": "2018-04-26"
}
],
"cancelled_quantity": 0,
"cancelled_info": null,
"returned_quantity": 0,
"returned_info": null
},
{
"item_id": "99",
"type": "discount",
"description": "Discount following our email conversation",
"metadata": {},
"reference": "",
"category": "",
"supplier_id": "",
"supplier_name": "",
"quantity": "1.000",
"unit_price": -120,
"tax_rate": "20.00",
"total_amount": -120,
"tax_amount": -20,
"fulfilled_quantity": 0,
"fulfillment_info": null,
"cancelled_quantity": 0,
"cancelled_info": null,
"returned_quantity": 0,
"returned_info": null
}
],
"metadata": {
"customer_id": "2055b445-3d95-4d2f-bd80-3e336217905f",
"checkout_id": "c0185e68-89aa-42d5-93e9-476d01d4c97f"
},
"payment_offer": "offer-cqfxJVUwXBrkyZHRQaknJS",
"deferred_payment": "defpay-7PiKMX2gEpJmasb8Du65zn"
}
If a customer files a complaint, but does not return any items, and you want to refund some of the money, you can send us an unspecified refund or discount.
This refund or discount becomes a new line of the Order
.
Disputes
If a customer files a complaint on a shipped order, and you can’t settle the dispute in a timely manner, we need to make sure, that we don’t debit the customer before the dispute is resolved. For that reason you need to send us a dispute notification, that then needs to be lifted once the dispute has been resolved.
As a result of an accepted dispute notification Hokodo will refrain from debiting the customer until the dispute has been actively resolved.
Note: If we already paid you, we will hold back the disputed sum from your next merchant payment until the dispute is resolved.
This endpoint is not available yet.
Payouts
A Payout represents a payment made from Hokodo to your bank account. It consists of the amount, date, and currency of the payout, as well as a list of individual Order changes and adjustments which were used to calculate the payout amount.
To facilitate cash reconciliation, each Payout object includes a unique payout reference id which can be found on your bank statement.
Payout endpoints
GET /v1/payment/payouts
GET /v1/payment/payouts/<payout_id>
GET /v1/payment/payout_items
GET /v1/payment/payout_items/<payout_item_id>
Payout object
{
"url": "https://api-sandbox.hokodo.co/v1/payment/payouts/po-yQKxbtCg9aTS5JYnsRVA9B",
"id": "po-yQKxbtCg9aTS5JYnsRVA9B",
"payout_reference_id": "HK-XYZ",
"payout_date": "2022-01-01",
"amount_from_payout_items": 12000,
"amount_from_adjustments": 1000,
"fees": 1000,
"type": "net_of_fees",
"amount": 12000,
"currency": "GBP",
"min_balance": {
"fixed": 1000,
"relative": 500,
"actual": 1000,
"withheld_amount": 2000
},
"items": [
{
"url": "https://api-sandbox.hokodo.co/v1/payment/payout_items/poitm-yQKxbtCg9aTS5JYnsRVA9B",
"id": "poitm-yQKxbtCg9aTS5JYnsRVA9B",
"type": "fulfilment",
"payout": "po-yQKxbtCg9aTS5JYnsRVA9B",
"deferred_payment": "defpay-yQKxbtCg9aTS5JYnsRVA9B",
"order": "order-yQKxbtCg9aTS5JYnsRVA9B",
"status": "paid",
"creation_date": "2021-12-26",
"earliest_payout_date": "2022-01-01",
"actual_payout_date": "2022-01-01",
"amount": 1100,
"fees": 100,
"amount_net_of_fees": 1000,
"currency": "GBP"
},
{
"url": "https://api-sandbox.hokodo.co/v1/payment/payout_items/poitm-yQKxbtCg9aTS5JYnsRVA9B",
"id": "poitm-yQKxbtCg9aTS5JYnsRVA9B",
"type": "fulfilment",
"payout": "po-yQKxbtCg9aTS5JYnsRVA9B",
"deferred_payment": "defpay-yQKxbtCg9aTS5JYnsRVA9B",
"order": "order-yQKxbtCg9aTS5JYnsRVA9B",
"status": "paid",
"creation_date": "2021-12-26",
"earliest_payout_date": "2022-01-01",
"actual_payout_date": "2022-01-01",
"amount": 1100,
"fees": 100,
"amount_net_of_fees": 1000,
"currency": "GBP"
}
],
"adjustments": [
{
"id": "poadj-yQKxbtCg9aTS5JYnsRVA9B",
"type": "credit_review_fee",
"net_amount": 400,
"tax_rate": 25,
"amount": 500,
"currency": "GBP"
},
{
"id": "poadj-yQKxbtCg9aTS5JYnsRVA9B",
"type": "minimum_fee",
"net_amount": 400,
"tax_rate": 25,
"amount": 500,
"currency": "GBP"
}
]
}
field | type | description |
---|---|---|
url | string | API endpoint to access the Payout |
id | string(uuid) | API unique identifier for the Payout |
payout_reference_id | string | Id which appears on your bank statement |
payout_date | date | Date the payout was made (i.e. when Hokodo initiated the transfer of funds to your bank account) |
amount_from_payout_items | int | Total amount of payout_items including any applicable fees, in minor units (cents) |
amount_from_adjustments | int | Total amount of adjustments in minor units (cents) |
fees | int | Total amount of fees in minor units (cents) |
type | string | How are your Payouts structured? net_of_fees or gross_of_fees |
amount | int | Amount paid to your bank account in minor units (cents). See calculating the payout amount |
currency | string (ISO 4217 code) | Currency of the payout |
min_balance | dictionary | Minimum account balance parameters at the time the payout was made |
min_balance[fixed] | int | Your fixed minimum account balance at the time the payout was made |
min_balance[relative] | int | Your relative minimum account balance (as a % of unpaid Orders) at the time the payout was made |
min_balance[actual] | int | The actual minimum balance used when calculating the payout amount. It is the max of fixed or relative |
min_balance[withheld_amount] | int | Total amount of payout items (e.g. fulfilled Order items) which were not included in this payout, in order to maintain your minimum account balance |
payout_items | list | List of payout items included in the payout |
adjustments | list | List of adjustments which were included in the payout_amount |
adjustments[*][id] | string(uuid) | API identifier for the Adjustment |
adjustments[*][type] | string | Type of adjustment (see Adjustment Type section) |
adjustments[*][net_amount] | int | Net amount for this adjustment (excluding tax) in minor units (cents) |
adjustments[*][tax_rate] | decimal | Tax rate on this adjustment, in percent (e.g. "19.50" for 19.5%) |
adjustments[*][amount] | int | Total amount for this adjustment (including tax) in minor units (cents) |
adjustments[*][currency] | string (ISO 4217 code) | Currency of the adjustment |
Calculating the payout amount
The final payout amount takes a number of factors into account:
- Total value of the payout items
- Total value of the any adjustments
- Your minimum account balance
- Whether your account is setup to receive payouts net or gross of fees
Minimum account balance
Your Hokodo account contains two minimum account balance parameters:
- Fixed: This is your fixed minimum account balance (e.g. €1,000). This amount will be determined before onboarding.
- Relative: This is your relative minimum account balance as a % of current unpaid Orders on your account. This % will be determined before onboarding.
When calculating the amount for an upcoming payout, Hokodo will compute your current minimum account balance min_balance[actual]
. This is the maximum of your fixed or relative minimum account balance.
Hokodo may withhold a number of PayoutItems needed to maintain this balance.
The total amount of the withheld Payout items is stored in the Payout's min_balance[withheld_amount]
field.
Adjustment amount
The Adjustment amount can be positive or negative.
- A positive adjustment amount will increase the payout amount
- A negative adjustment amount will decrease the payout amount
Adjustment type
An adjustment can have one of the following types:
status | description |
---|---|
balancing_item | this is only used if adjustments are needed between successive payouts. Balancing items should always offset with items in preceding or subsequent months such that they should sum to zero |
minimum_fee | adjustment required if monthly transaction volumes don't achieve minimum fee |
credit_review_fee | fee for any credit reviews |
balance_carried_to_next_payout | amount carried over to next payout |
balance_carried_from_last_payout | amount carried over from last payout |
fee_discount | applied when any fees are waived |
fx_fee | fee incurred if any currency conversions are required as part of the payout |
other |
List Payouts
Request
GET /v1/payment/payouts HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/payment/payouts \
--header "Authorization: <your_api_key>"
Response
200 Ok
Content-Type: application/json
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"url": "https://api-sandbox.hokodo.co/v1/payment/payout/po-yQKxbtCg9aTS5JYnsRVA9B",
"id": "po-yQKxbtCg9aTS5JYnsRVA9B",
"payout_reference_id": "HK-XYZ",
"payout_date": "2022-01-01",
"amount_from_payout_items": 12000,
"amount_from_adjustments": 1000,
"fees": 1000,
"type": "net_of_fees",
"amount": 12000,
"currency": "GBP",
"min_balance": {
"fixed": 1000,
"relative": 500,
"actual": 1000,
"withheld_amount": 2000
},
"items": [
...
],
"adjustments": [
...
]
},
{
"url": "https://api-sandbox.hokodo.co/v1/payment/payout/po-yQKxbtCg9aTS5JYnsRVA9B",
"id": "po-yQKxbtCg9aTS5JYnsRVA9B",
"payout_reference_id": "HK-XYZ",
"payout_date": "2022-01-01",
"amount_from_payout_items": 12000,
"amount_from_adjustments": 1000,
"fees": 1000,
"type": "net_of_fees",
"amount": 12000,
"currency": "GBP",
"min_balance": {
"fixed": 1000,
"relative": 500,
"actual": 1000,
"withheld_amount": 2000
},
"items": [
...
],
"adjustments": [
...
]
}
]
}
View Payout
Request
GET /v1/payment/payouts/<payout_id> HTTP/1.1
Authorization: Token <your_api_key>
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/payment/payouts/<payout_id> \
--header "Authorization: <your_api_key>"
Responses
- regular response
200 Ok
Content-Type: application/json
{
"url": "https://api-sandbox.hokodo.co/v1/payment/payouts/po-yQKxbtCg9aTS5JYnsRVA9B",
"id": "po-yQKxbtCg9aTS5JYnsRVA9B",
"payout_reference_id": "HK-XYZ",
"payout_date": "2022-01-01",
"amount_from_payout_items": 12000,
"amount_from_adjustments": 1000,
"fees": 1000,
"type": "net_of_fees",
"amount": 12000,
"currency": "GBP",
"min_balance": {
"fixed": 1000,
"relative": 500,
"actual": 1000,
"withheld_amount": 2000
},
"items": [
{
"url": "https://api-sandbox.hokodo.co/v1/payment/payout_items/poitm-yQKxbtCg9aTS5JYnsRVA9B",
"id": "poitm-yQKxbtCg9aTS5JYnsRVA9B",
"type": "fulfilment",
"payout": "po-yQKxbtCg9aTS5JYnsRVA9B",
"deferred_payment": "defpay-yQKxbtCg9aTS5JYnsRVA9B",
"order": "order-yQKxbtCg9aTS5JYnsRVA9B",
"status": "paid",
"creation_date": "2021-12-26",
"earliest_payout_date": "2022-01-01",
"actual_payout_date": "2022-01-01",
"amount": 1100,
"fees": 100,
"amount_net_of_fees": 1000,
"currency": "GBP"
},
{
"url": "https://api-sandbox.hokodo.co/v1/payment/payout_items/poitm-yQKxbtCg9aTS5JYnsRVA9B",
"id": "poitm-yQKxbtCg9aTS5JYnsRVA9B",
"type": "fulfilment",
"payout": "po-yQKxbtCg9aTS5JYnsRVA9B",
"deferred_payment": "defpay-yQKxbtCg9aTS5JYnsRVA9B",
"order": "order-yQKxbtCg9aTS5JYnsRVA9B",
"status": "paid",
"earliest_payout_date": "2022-01-01",
"actual_payout_date": "2022-01-01",
"amount": 1100,
"fees": 100,
"amount_net_of_fees": 1000,
"currency": "GBP"
}
],
"adjustments": [
{
"id": "poadj-yQKxbtCg9aTS5JYnsRVA9B",
"type": "credit_review_fee",
"net_amount": 100,
"tax_rate": 10,
"amount": 110,
"currency": "GBP"
},
{
"id": "poadj-yQKxbtCg9aTS5JYnsRVA9B",
"type": "minimum_fee",
"net_amount": 200,
"tax_rate": 10,
"amount": 220,
"currency": "GBP"
}
]
}
- Not Found
404 Not Found
Content-Type: application/json
{
"detail": "Not found."
}
Query Params
GET /v1/payment/payouts?start_date=2022-01-01&end_date=2022-02-01 HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
curl --request GET \
--url "https://api-sandbox.hokodo.co/v1/payment/payouts?start_date=2022-01-01&end_date=2022-02-01" \
--header "Authorization: <your_api_key>"
Response
200 Ok
Content-Type: application/json
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"url": "https://api-sandbox.hokodo.co/v1/payment/payout/po-yQKxbtCg9aTS5JYnsRVA9B",
"id": "po-yQKxbtCg9aTS5JYnsRVA9B",
"payout_reference_id": "HK-XYZ",
"payout_date": "2022-01-01",
"amount_from_payout_items": 12000,
"amount_from_adjustments": 1000,
"fees": 1000,
"type": "net_of_fees",
"amount": 12000,
"currency": "GBP",
"min_balance": {
"fixed": 1000,
"relative": 500,
"actual": 1000,
"withheld_amount": 2000
},
"items": [
...
],
"adjustments": [
...
]
},
{
"url": "https://api-sandbox.hokodo.co/v1/payment/payout/po-yQKxbtCg9aTS5JYnsRVA9B",
"id": "po-yQKxbtCg9aTS5JYnsRVA9B",
"payout_reference_id": "HK-XYZ",
"payout_date": "2022-01-01",
"amount_from_payout_items": 12000,
"amount_from_adjustments": 1000,
"fees": 1000,
"type": "net_of_fees",
"amount": 12000,
"currency": "GBP",
"min_balance": {
"fixed": 1000,
"relative": 500,
"actual": 1000,
"withheld_amount": 2000
},
"items": [
...
],
"adjustments": [
...
]
}
]
}
When you want to search for a specific Payout (e.g. a Payout with a certain payout_reference_id
) or a specific set of Payouts (e.g. all Payouts from the last quarter), the query params below can be applied to the Payout's endpoint.
param | type | description |
---|---|---|
start_date | date | Include payouts made to your account on or after this date |
end_date | date | Include payouts made to your account on or before this date |
payout_reference_id | string | Only include the Payout with this payout_reference_id |
PayoutItem object
{
"url": "https://api-sandbox.hokodo.co/v1/payment/payout_items/poitm-yQKxbtCg9aTS5JYnsRVA9B",
"id": "poitm-yQKxbtCg9aTS5JYnsRVA9B",
"type": "fulfilment",
"payout": null,
"deferred_payment": "defpay-yQKxbtCg9aTS5JYnsRVA9B",
"order": "order-yQKxbtCg9aTS5JYnsRVA9B",
"status": "scheduled",
"creation_date": "2021-12-26",
"earliest_payout_date": "2022-02-01",
"actual_payout_date": null,
"amount": 1100,
"fees": 100,
"amount_net_of_fees": 1000,
"currency": "GBP"
}
A Payout typically contains one or more PayoutItems. A PayoutItem provides a direct link between a post sale event (e.g. capture/fulfilment, refund/return, clawback) and the subsequent Payout.
field | type | description |
---|---|---|
url | string | API endpoint to access the PayoutItem |
id | string(uuid) | API identifier for the PayoutItem |
type | string | Type of PayoutItem, which describes the reason for paying out this item. |
payout | string(uuid) | API identifier of the underlying Payout. This will be null for PayoutItems which are scheduled to be paid but haven't been paid yet. |
deferred_payment | string(uuid) | API identifier of the underlying DeferredPayment. To view all fields for this DeferredPayment, include expand=deferred_payment in your request's query params |
order | string(uuid) | API identifier of the underlying Order. To view all fields for this Order, include expand=order in your request's query params |
status | string | Status of the PayoutItem (scheduled , paid , or awaiting_document ) |
creation_date | date | Date the PayoutItem was created |
earliest_payout_date | date | Earliest possible date this item will be paid |
actual_payout_date | date | Actual date this item was paid. This will be null for items which haven't been paid |
amount | int | Total amount of the PayoutItem (i.e. total amount of the underlying Order change) in minor units (cents) before any fees |
fees | int | Fees which have been applied (or will apply) to this PayoutItem in minor units (cents) |
amount_net_of_fees | int | Net amount for this PayoutItem (i.e. amount - fees ) in minor units (cents). Note that depending on your payout settings the actual cash paid to you may be the amount or the amount_net_of_fees. This is stated in the Payout payout_structure field |
currency | string (ISO 4217 code) | Currency of the PayoutItem |
deferred_payment_event_metadata | dictionary | A copy of the metadata you added to the post-sale call, which generated this payout-item |
Payout Item Type
type | description |
---|---|
fulfilment | occurs when you notify us of a capture/fulfilment |
return | occurs when you notify us of a refund/return |
discount (deprecated) | occurs when you notify us of a refund/discount in our old post-sale endpoint |
fraud_clawback | occurs when the order has not been paid due to fraud, where the order is not fraud protected with Hokodo. |
credit_clawback | occurs when the order is not fully credit protected with Hokodo, and the order is never paid. |
misdirected_payment_clawback | occurs when the bank transfer payment was received in the incorrect bank accounts (either Hokodo or the Merchant) |
other_clawback | occurs for any other cases where Hokodo needs to clawback funds from the Merchant payout. |
For the clawback types, they are the reversal of already paid out captures. No clawback will occur if the order has not been captured.
note: We may reverse clawback, either due to human error, or an exceptionally late buyer payment recovery. In this scenario the credit_clawback
or fraud_clawback
types will still be used. The items will just have positive values, indicating money is being paid out to you.
List PayoutItems
Request
GET /v1/payment/payout_items HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/payment/payout_items \
--header "Authorization: <your_api_key>"
Response
200 Ok
Content-Type: application/json
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"url": "https://api-sandbox.hokodo.co/v1/payment/payout_items/poitm-yQKxbtCg9aTS5JYnsRVA9B",
"id": "poitm-yQKxbtCg9aTS5JYnsRVA9B",
"type": "fulfilment",
"payout": null,
"deferred_payment": "defpay-yQKxbtCg9aTS5JYnsRVA9B",
"order": "order-yQKxbtCg9aTS5JYnsRVA9B",
"status": "scheduled",
"creation_date": "2021-12-26",
"earliest_payout_date": "2022-02-01",
"actual_payout_date": null,
"amount": 1100,
"fees": 100,
"amount_net_of_fees": 1000,
"currency": "GBP"
},
{
"url": "https://api-sandbox.hokodo.co/v1/payment/payout_items/poitm-yQKxbtCg9aTS5JYnsRVA9B",
"id": "poitm-yQKxbtCg9aTS5JYnsRVA9B",
"type": "fulfilment",
"payout": null,
"deferred_payment": "defpay-yQKxbtCg9aTS5JYnsRVA9B",
"order": "order-yQKxbtCg9aTS5JYnsRVA9B",
"status": "scheduled",
"creation_date": "2021-12-26",
"earliest_payout_date": "2022-02-01",
"actual_payout_date": null,
"amount": 1100,
"fees": 100,
"amount_net_of_fees": 1000,
"currency": "GBP"
}
]
}
View PayoutItem
Request
GET /v1/payment/payout_items/<payout_item_id> HTTP/1.1
Authorization: Token <your_api_key>
curl --request GET \
--url https://api-sandbox.hokodo.co/v1/payment/payout_items/<payout_item_id> \
--header "Authorization: <your_api_key>"
Responses
- regular response
200 Ok
Content-Type: application/json
{
"url": "https://api-sandbox.hokodo.co/v1/payment/payout_items/poitm-yQKxbtCg9aTS5JYnsRVA9B",
"id": "poitm-yQKxbtCg9aTS5JYnsRVA9B",
"type": "fulfilment",
"payout": null,
"deferred_payment": "defpay-yQKxbtCg9aTS5JYnsRVA9B",
"order": "order-yQKxbtCg9aTS5JYnsRVA9B",
"status": "scheduled",
"creation_date": "2021-12-26",
"earliest_payout_date": "2022-02-01",
"actual_payout_date": null,
"amount": 1100,
"fees": 100,
"amount_net_of_fees": 1000,
"currency": "GBP"
}
- Not Found
404 Not Found
Content-Type: application/json
{
"detail": "Not found."
}
Query Params
GET /v1/payment/payout_items?order_unique_id=xxx HTTP/1.1
Content-Type: application/json
Authorization: Token <your_api_key>
curl --request GET \
--url "https://api-sandbox.hokodo.co/v1/payment/payout_items?order_unique_id=xxx" \
--header "Authorization: <your_api_key>"
Response
200 Ok
Content-Type: application/json
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"url": "https://api-sandbox.hokodo.co/v1/payment/payout_items/poitm-yQKxbtCg9aTS5JYnsRVA9B",
"id": "poitm-yQKxbtCg9aTS5JYnsRVA9B",
"type": "fulfilment",
"payout": null,
"deferred_payment": "defpay-yQKxbtCg9aTS5JYnsRVA9B",
"order": "order-yQKxbtCg9aTS5JYnsRVA9B",
"status": "scheduled",
"creation_date": "2021-12-26",
"earliest_payout_date": "2022-02-01",
"actual_payout_date": null,
"amount": 1100,
"fees": 100,
"amount_net_of_fees": 1000,
"currency": "GBP"
}
]
}
When you want to search for a specific set of PayoutItems (e.g. all PayoutItems attached to a specific Order), the query params below can be applied to the PayoutItems endpoint.
param | type | description |
---|---|---|
order_id | string(uuid) | API identifier for the Order |
order_unique_id | string(uuid) | Unique identifier of the order on your platform |
start_date | date | Include payouts made to your account on or after this date. |
end_date | date | Include payouts made to your account on or before this date. |
Webhooks / Notifications / Callbacks
Hokodo uses webhooks to notify your application when an event happens in your account. For example, when one of your customers has their deferred payment application approved.
Webhooks allow you to avoid polling and instead receive notifications when changes related to an Order
, Offer
or DeferredPayment
object occur.
Webhook Payload
Sample content
Deferred Payment Application Complete
{
"created": "2021-01-01T12:00:00Z",
"data": {
"order": {
"id": "order-QWLGzh3ciDXo3P4QkPtrnH",
"unique_id": "",
"po_number": "",
"customer": {
"organisation": {
"id": "org-mSuTHdaodb5pjDmKsBj5Z4",
"unique_id": "1",
"registered": "2010-06-30T00:00:00Z",
"company": null,
"users": [
"96608083-4783-44e3-a474-4bad3fa6e82a"
]
},
"user": {
"id": "user-pHm3kfFQXwzs8ND8HYNTYV",
"email": "syTnvfVbZjFv@email.com",
"unique_id": "",
"name": "name_SUUgVUVuRVaB",
"phone": "",
"registered": "2010-06-30T00:00:00Z",
"type": "registered"
},
"invoice_address": {
"name": "name_LGDZJAFYLRus",
"company_name": "company_name_touyMqWkVyAn",
"address_line1": "address_line1_gKmCACesrqbd",
"address_line2": "address_line2_shliflLciPie",
"address_line3": "",
"city": "city_edqpaQOKqUXI",
"region": "",
"postcode": "E1 1D0",
"country": "GB",
"phone": "",
"email": ""
},
"delivery_address": {
"name": "name_tLoyeGeGMXlc",
"company_name": "company_name_DgcvLcFejRbl",
"address_line1": "address_line1_XKWMakHAilHa",
"address_line2": "address_line2_MzczHXdoRqQR",
"address_line3": "",
"city": "city_jSjusADEJkuE",
"region": "",
"postcode": "E1 1D1",
"country": "GB",
"phone": "",
"email": ""
},
"billing_address": {
"name": "name_LGDZJAFYLRus",
"company_name": "company_name_touyMqWkVyAn",
"address_line1": "address_line1_gKmCACesrqbd",
"address_line2": "address_line2_shliflLciPie",
"address_line3": "",
"city": "city_edqpaQOKqUXI",
"region": "",
"postcode": "E1 1D0",
"country": "GB",
"phone": "",
"email": ""
}
},
"created": "2020-11-10T08:31:39.915557Z",
"currency": "EUR",
"order_date": "2020-11-10",
"invoice_date": null,
"due_date": null,
"paid_date": null,
"total_amount": 1000,
"tax_amount": 200,
"metadata": null,
"items": [
{
"item_id": "0",
"type": "",
"description": "",
"metadata": null,
"reference": "",
"category": "",
"supplier_id": "",
"supplier_name": "",
"quantity": "10.000",
"unit_price": 100,
"total_amount": 1000,
"tax_amount": 200,
"tax_rate": "25.00"
}
],
"payment_offer": {
"url": "/v1/payment/offers/offr-SFRufpfb4wMh8Jkr84W8Gf",
"id": "offr-SFRufpfb4wMh8Jkr84W8Gf",
"order": "order-QWLGzh3ciDXo3P4QkPtrnH",
"offered_payment_plans": [
{
"id": "ppln-E8tWZ3MahpeDp798k9fzVH",
"name": "",
"template": "pptemp-MNhaDZyoRatSZTyizGTgtb",
"currency": "EUR",
"protected_amount": 1000,
"unprotected_amount": 0,
"scheduled_payments": [
{
"date": "2021-01-31",
"amount": 1000,
"discounted_amount": 1000,
"customer_fee": {
"percentage": "0.00",
"amount": 0
},
"allowed_payment_methods": [
{
"type": "direct_debit"
},
{
"type": "invoice"
},
{
"type": "card"
}
],
"payment_method": {"type": "invoice"},
"due_date_config": {
"due_after_nb_days": null,
"due_end_of_nb_months": 0,
"amount_percentage": "100.0",
"is_upfront_payment": false
}
}
],
"payment_terms_relative_to": "order_creation",
"merchant_fee": {
"currency": "EUR",
"amount": 0
},
"customer_fee": {
"currency": "EUR",
"percentage": "0.00",
"amount": 0
},
"customer_percentage_discount": "0.00",
"customer_discount": {
"currency": "EUR",
"amount": 0
},
"valid_until": "2020-11-17T08:31:40.059Z",
"payment_url": "https://api-sandbox.hokodo.co/?order=order-QWLGzh3ciDXo3P4QkPtrnH&plan=ppln-E8tWZ3MahpeDp798k9fzVH&key=cjuHbDjF3txeTaHgtDUilQ9UdYqHllC2iFFarKdJemU&template=pptemp-MNhaDZyoRatSZTyizGTgtb",
"status": "offered",
"rejection_reason": null,
"has_upfront_payment": false
}
],
"urls": {
"success": "",
"failure": "",
"cancel": "",
"notification": "",
"merchant_terms": ""
},
"locale": "",
"metadata": null
},
"deferred_payment": {
"url": "/v1/payment/deferred_payments/defpay-8BvTZ9T6K5gj6LeSqvfqzm",
"id": "defpay-8BvTZ9T6K5gj6LeSqvfqzm",
"number": "P-PMNE-DN6C",
"payment_plan": {
"id": "ppln-E8tWZ3MahpeDp798k9fzVH",
"name": "",
"template": "pptemp-MNhaDZyoRatSZTyizGTgtb",
"currency": "EUR",
"protected_amount": 1000,
"unprotected_amount": 0,
"scheduled_payments": [
{
"date": "2021-01-31",
"amount": 1000,
"discounted_amount": 1000,
"customer_fee": {
"percentage": "0.00",
"amount": 0
},
"allowed_payment_methods": [
{
"type": "direct_debit"
},
{
"type": "invoice"
},
{
"type": "card"
}
],
"payment_method": {"type": "invoice"},
"due_date_config": {
"due_after_nb_days": null,
"due_end_of_nb_months": 0,
"amount_percentage": "100.0",
"is_upfront_payment": false
}
}
],
"payment_terms_relative_to": "order_creation",
"merchant_fee": {
"currency": "EUR",
"amount": 0
},
"customer_fee": {
"currency": "EUR",
"percentage": "0.00",
"amount": 0
},
"customer_percentage_discount": "0.00",
"customer_discount": {
"currency": "EUR",
"amount": 0
},
"valid_until": "2020-11-17T08:31:40.059Z",
"payment_url": "https://api-sandbox.hokodo.co/?order=order-QWLGzh3ciDXo3P4QkPtrnH&plan=ppln-E8tWZ3MahpeDp798k9fzVH&key=cjuHbDjF3txeTaHgtDUilQ9UdYqHllC2iFFarKdJemU&template=pptemp-MNhaDZyoRatSZTyizGTgtb",
"status": "offered",
"rejection_reason": null,
"has_upfront_payment": false
},
"order": "order-QWLGzh3ciDXo3P4QkPtrnH",
"outstanding_balance": {
"amount": null,
"currency": "EUR"
},
"next_payment_date": null,
"payments": null,
"status": "part_captured",
"repayment_info": null,
"authorisation": 800,
"currency": "EUR",
"protected_captures": 200,
"unprotected_captures": 0,
"refunds": 0,
"voided_authorisation": 0,
"expired_authorisation": 0,
"clawback_amount": 0,
"events": [
{
"created": "2023-01-05T09:55:38.091854Z",
"type": "capture",
"amount": 200,
"currency": "EUR",
"metadata": {
"note": "Capturing 1000 worth of bonbons"
},
"changes": {
"authorisation": -200,
"protected_captures": 200,
"unprotected_captures": 0,
"refunds": 0,
"voided_authorisation": 0,
"expired_authorisation": 0,
"clawback": 0,
"customer_fee": {
"authorisation": 0,
"captures": 0,
"refunds": 0,
"voided_authorisation": 0,
"expired_authorisation": 0
}
}
}
]
},
"status": "draft",
"pay_method": "unknown"
}
}
}
The webhook payload will include a full Order
object.
field | type | description |
---|---|---|
created | string | Time the notification was sent (e.g. 2021-01-01T12:00:00Z) |
data | dictionary | Dictionary containing the Order object |
data[order] | dictionary | The Order object |
The Order
object will have the following fields expanded(if available):
- customer: the
Customer
object - items: the list of order items
- payment_offer: the
Offer
object with the full list of linkedPaymentPlan
objects inside an expanded fieldoffered_payment_plans
- deferred_payment: the
DeferredPayment
object which has been created after customer approval, with the expanded fieldpayment_plan
that contains the correspondingPaymentPlan
object
Events
You will receive a notification when any of the following events occur:
Order
creationOrder
updateOffer
creationOffer
updateDeferredPayment
creationDeferredPayment
update
Please note that the payload for all of the events will contain the latest version of the Order
object with the expanded fields (if available) as described above.
Getting Started
1. Select Integration Option
Depending on your use-case Hokodo can configure your account so that all notifications will be sent to the same webhook. Alternatively, when you create an Offer
you can include a notification
url
in the request, and we'll send all notifications related to that specific Offer
to this url. Changes to related objects such as the underlying Order
or a DeferredPayment
will also be sent to this url.
If you prefer the first option please let us know at support@hokodo.co and we will be happy to configure your account.
No additional setup is required if you prefer the second option. Note, if you do select this option, you won't receive any notifications about Order
changes until you create an Offer
.
2. Secure Your Webhook (optional)
For enhanced security, Hokodo can include an authentication string in the Authorization
header of all notifications.
If you're interested in this option please let us know at support@hokodo.co
Notes
Your endpoint must be using HTTPS.
In production, our API will verify the validity of the HTTPS certificate. In sandbox, you can use a self-signed certificate.
Our API will send a POST request, with the content of the
Order
in the POST request body as JSON.Our API expects a
2xx
status code from your endpoint for a successful response.Our API will retry up to 3 times if it can't connect successfully to your endpoint. It will wait 0, 2, and 4 seconds respectively before the 1st, 2nd and 3rd retry.
Error codes
The Hokodo API uses the following error codes:
Error Code | Meaning |
---|---|
400 | Bad Request -- Your request is invalid. |
401 | Unauthorized -- Your API key is wrong. |
403 | Forbidden -- The requested function is not available for your account. |
404 | Not Found -- The specified object could not be found. |
405 | Method Not Allowed -- You tried to access an object with an invalid method. |
409 | Conflict -- The requested action conflicts with the current state of the object. |
429 | Too Many Requests -- See Rate Limiting for more details. |
500 | Internal Server Error -- We had a problem with our server. Try again later. |
503 | Service Unavailable -- We're temporarily offline for maintenance. Please try again later. |
Testing in sandbox
Bypass underwriting engine
To facilitate testing in Sandbox, you can bypass the underwriting engine to create Offers
with specific statuses and so test their behaviour in your checkout.
This bypasses our Underwriting engine, which determines the Offer
status.
To create an Offer
with a specific status, you need to create a User
with an email corresponding to a specific pattern, and use that User
to create your order.
For example, if you would like to test an Offer
that is rejected during underwriting, set the User
email to myuser+paymentplan_declined@mail.com
.
Searched pattern | Payment Plan Status | Example |
---|---|---|
paymentplan_offered |
offered |
sandrine_bouchon+paymentplan_offered@yourdomain.com |
paymentplan_declined |
declined |
gerard_colins+paymentplan_declined@yourdomain.com |
paymentplan_partly_offered |
one offered , the others declined |
gerard_colins+paymentplan_partly_offered@yourdomain.com |
- This will automatically make your offer
offered
ordeclined
for underwriting reasons. Therejection_reason
will be filled with a generic reason. partly_offered
is not a realOffer
status, but allows you to have bothoffered
anddeclined
payment plans within the same offer: If we have configured your account such that multiplePaymentPlans
are generated following anOffer
request, onePaymentPlan
will beoffered
and the other one(s)declined
.
Bypass fraud engine
To facilitate testing in Sandbox, you can create DeferredPayments
with specific statuses and so test their behaviour in your checkout.
This bypasses our fraud engine, which determines the DeferredPayment
status.
To create a DeferredPayment
with a specific status, you need to create a User
with an email corresponding to a specific pattern,
and use that User
to create your order.
For example, if you would like to test a DP with an accepted
status, set the User
email to myuser_dp_fraud_accepted@yourdomain.com
.
Searched pattern | Deferred Payment Status | Example |
---|---|---|
dp_fraud_accepted |
accepted |
sandrine_bouchon+dp_fraud_accepted@yourdomain.com |
dp_fraud_rejected |
rejected |
gerard_colins+dp_fraud_rejected@yourdomain.com |
dp_fraud_customer_action_required |
customer_action_required |
dp_fraud_customer_action_required_fatou_ndial@yourdomain.com |
dp_fraud_pending_review |
pending_review |
kevin_fischer+dp_fraud_pending_review@yourdomain.com |
Combine underwriting and fraud pattern
You can combine both patterns to test different combinations of Offer
and DeferredPayment
status. For example:
Searched pattern | Payment Plan Status | Deferred Payment Status |
---|---|---|
paymentplan_offered_dp_fraud_accepted |
offered |
accepted |
paymentplan_offered_dp_fraud_rejected |
offered |
rejected |
paymentplan_declined_dp_fraud_accepted |
declined |
never get to fraud detection |
paymentplan_partly_offered_dp_fraud_pending_review |
one offered , the others declined |
pending_review |
If the offer is declined, you cannot create a Deferred Payment.
Important note
If two different fraud or payment plan status are found (dp_fraud_accepted_dp_fraud_rejected@mail.com
), the first match is taken.
When testing from sandbox, we are sending emails, to properly test:
- The domain should be a real one,
- We suggest to use subaddressing or alias for your test. (for example
sandrine_bouchon+dp_fraud_accepted@yourdomain.com
)