Create a contract with products
You can create a contract and set products in your product table in a few steps.
Step 1. Check if the template can receive products
Note:
To add products to a contract via the API, the contract's template should contain one or more product tables. Product tables can be added via Oneflow's web app. You may then use Oneflow's API to create a contract using the template while adding products to its product tables.
When you create a contract with products, and the contract template already contains a product table, the system will replace the template product table with the contract’s product table.
There are two ways to check if the template you use can receive products:
- Check the template in the Oneflow application. Go to the Templates page and open your template.
A template can contain one or more product tables.
- Check the
can_receive_products
attribute in the template's available_options object.
Step 2. Obtain necessary information
To run the script described in this tutorial, you’ll need the following data:
Headers | |
x-oneflow-api-token
|
You will only be able to run the script by using a valid API token. You can create an API token in the Oneflow web application. Find more in the Authentication section. |
x-oneflow-user-email
|
Your Oneflow user account email. You can find all user-related information using the users endpoint. |
Body | |
workspace_id
|
The unique ID of the workspace where you want to create your contract. You can find the workspace ID using the workspaces endpoint. |
template_id
|
The unique ID of the template you want to use for creating your contract. You can find the template ID using the templates endpoint. |
Product groups | |
product_groups
|
A product group is the equivalent of a product table in the Oneflow application. Each product group contains a list of products. The maximum amount of products per contract is limited to 150. A contract can contain multiple product groups. |
id
|
The ID of the product group (product table) in the template. Each product group will have its own unique ID. You can get the ID of a product group by sending a GET request to the templates endpoint along with the template ID as a path parameter. |
configuration
|
The configuration of this product group. |
products [array]
|
The array of products in this group. |
name
|
Product name. |
quantity
|
Product quantity. |
Step 3. Run the code
Scenario 1: Create a contract from a template with one product group
Note:
If your template contains exactly one product group, then it is not mandatory to include the
id
in the request body.
Replace the values of the parameters in the following command with the actual data from your account and run it:
curl --request POST \
--url https://api.oneflow.com/v1/contracts/create \
--header 'content-type: application/json' \
--header 'x-oneflow-api-token: API_TOKEN' \
--header 'x-oneflow-user-email: USER_EMAIL' \
--data '{
"workspace_id": WORKSPACE_ID,
"template_id": TEMPLATE_ID,
"name": "",
"product_groups": [{
"products": [
{
"name": "Swatch Smart Watch",
"counterparty_lock": false,
"description": "The smartest watch on the market.",
"price_1": {"base_amount": {"amount": "20000"}, "discount_amount": {"amount": "100.00"}},
"price_2": {"base_amount": {"amount": "1000"}, "discount_percent": "5"},
"quantity": {"amount": 1, "type": "multiple_choice"}
},
{
"name": "Smart insurance",
"counterparty_lock": true,
"description": "Insure your watch for an additional 2 years!",
"price_1": {"base_amount": {"amount": "99.99"}},
"quantity": {"amount": 0, "type": "single_choice"}
},
{
"name": "Smart screen cover",
"counterparty_lock": false,
"description": "Protect your watch face!",
"price_1": {"base_amount": {"amount": "9.99"}},
"quantity": {"amount": 5, "type": "quantity"}
}
]}]
}'
import requests
headers = {
'content-type': 'application/json',
'x-oneflow-api-token': 'API_TOKEN',
'x-oneflow-user-email': 'USER_EMAIL',
}
data = {
'workspace_id': WORKSPACE_ID,
'template_id': TEMPLATE_ID,
'product_groups': [
{
'id': ORIGINAL_PRODUCT_GROUP_ID,
'configuration':{
'counterpart_edit':True,
'columns':[
{
'enabled':False,
'key':'name',
'label':'New Product column name'
}
],
'hide_price_summation':False,
'price_affixes':{
'postfix':'',
'prefix':'$'
}
},
'products': [
{
'name': 'Swatch Smart Watch',
'counterparty_lock': False,
'description': 'The smartest watch on the market.',
'price_1': {
'base_amount': {
'amount': '20000'
},
'discount_amount': {
'amount': '100.00'
}
},
'price_2': {
'base_amount': {
'amount': '1000'
},
'discount_percent': '5'
},
'quantity': {
'amount': 1,
'type': 'multiple_choice'
},
},
{
'name': 'Smart insurance',
'counterparty_lock': False,
'description': 'Insure your watch for an additional 2 years!',
'price_1': {
'base_amount': {
'amount': '99.99'
}
},
'quantity': {
'amount': 0,
'type': 'single_choice'
},
},
{
'name': 'Smart screen cover',
'counterparty_lock': True,
'description': 'Protect your watch face!',
'price_1': {
'base_amount': {
'amount': '9.99'
}
},
'quantity': {
'amount': 5,
'type': 'quantity'
},
},
],
},
],
}
response = requests.post('https://api.oneflow.com/v1/contracts/create',
headers=headers, json=data)
print(response.json())
This command should result in a contract with a product table like this:
Note:
You should also adapt the product table’s headers in the template in the Oneflow application.
Expected response
This request will output details about the contract with products you created in the JSON format:
{
...
"product_groups":[
{
"_private_ownerside":{
"created_time":"2021-03-17T11:49:02+00:00",
"updated_time":"2021-03-17T11:49:03+00:00"
},
"configuration":{
"columns":[
{
"enabled":false,
"key":"name",
"label":"New Product column name"
},
{
"enabled":true,
"key":"description",
"label":"Description"
},
{
"enabled":true,
"key":"price_1",
"label":"Price 1"
},
{
"enabled":true,
"key":"price_2",
"label":"Price 2"
},
{
"enabled":true,
"key":"count",
"label":"Value"
}
],
"counterpart_edit":true,
"hide_price_summation":false,
"name": {
"enabled": false,
"label": "Untitled"
},
"price_affixes":{
"postfix":"",
"prefix":"$"
},
"price_precision": 2,
"quantity_precision": 0
},
"created_from":80169,
"enabled_columns":[
{
"enabled":false,
"key":"name"
},
{
"enabled":true,
"key":"description"
},
{
"enabled":true,
"key":"price_1"
},
{
"enabled":true,
"key":"price_2"
},
{
"enabled":true,
"key":"count"
}
],
"id":110071,
"products":[
{
"_private_ownerside":{
"created_time":"2021-03-17T11:49:03+00:00",
"updated_time":null
},
"counterparty_lock":false,
"description":"The smartest watch on the market.",
"id":2919,
"name":"Swatch Smart Watch",
"price_1":{
"amount":{
"amount":"19900.00"
},
"base_amount":{
"amount":"20000.00"
},
"discount_amount":{
"amount":"100.00"
},
"discount_percent":"0.000"
},
"price_2":{
"amount":"950.00",
"base_amount":{
"amount":"1000.00"
},
"discount_amount":{
"amount":"0.00"
},
"discount_percent":"5.000"
},
"quantity":{
"amount":1,
"type":"multiple_choice"
}
},
{
"_private_ownerside":{
"created_time":"2021-03-17T11:49:03+00:00",
"updated_time":null
},
"counterparty_lock":true,
"description":"Insure your watch for an additional 2 years!",
"id":2920,
"name":"Smart insurance",
"price_1":{
"amount":{
"amount":"0.00"
},
"base_amount":{
"amount":"99.99"
},
"discount_amount":{
"amount":"0.00"
},
"discount_percent":"0.000"
},
"price_2":{
"amount":{
"amount":"0.00"
},
"base_amount":{
"amount":"0.00"
},
"discount_amount":{
"amount":"0.00"
},
"discount_percent":"0.000"
},
"quantity":{
"amount":0,
"type":"single_choice"
}
},
{
"_private_ownerside":{
"created_time":"2021-03-17T11:49:03+00:00",
"updated_time":null
},
"counterparty_lock":false,
"description":"Protect your watch face!",
"id":2921,
"name":"Smart screen cover",
"price_1":{
"amount":{
"amount":"0.00"
},
"base_amount":{
"amount":"9.99"
},
"discount_amount":{
"amount":"0.00"
},
"discount_percent":"0.000"
},
"price_2":{
"amount":{
"amount":"0.00"
},
"base_amount":{
"amount":"0.00"
},
"discount_amount":{
"amount":"0.00"
},
"discount_percent":"0.000"
},
"quantity":{
"amount":5,
"type":"quantity"
}
}
]
}
],
...
}
Please see the Product group section in the Data model category for more information about the output.
Scenario 2: Create a contract from a template with multiple product groups
Note:
If your template contains multiple product groups, you need to to include the
id
of each product group in the request body.
Replace the values of the parameters in the following command with the actual data from your account and run it:
curl --request POST \
--url 'https://api.oneflow.com/v1/contracts/create' \
--header 'content-type: application/json' \
--header 'x-oneflow-api-token: API_TOKEN' \
--header 'x-oneflow-user-email: USER_EMAIL' \
--data '{
"workspace_id": WORKSPACE_ID,
"template_id": TEMPLATE_ID,
"name": "",
"product_groups": [{
"id": PRODUCT_GROUP_ID,
"products": [
{
"name": "Swatch Smart Watch",
"counterparty_lock": false,
"description": "The smartest watch on the market.",
"price_1": {"base_amount": {"amount": "20000"}, "discount_amount": {"amount": "100.00"}},
"price_2": {"base_amount": {"amount": "1000"}, "discount_percent": "5"},
"quantity": {"amount": 1, "type": "multiple_choice"}
},
{
"name": "Smart insurance",
"counterparty_lock": true,
"description": "Insure your watch for an additional 2 years!",
"price_1": {"base_amount": {"amount": "99.99"}},
"quantity": {"amount": 0, "type": "single_choice"}
},
{
"name": "Smart screen cover",
"counterparty_lock": false,
"description": "Protect your watch face!",
"price_1": {"base_amount": {"amount": "9.99"}},
"quantity": {"amount": 5, "type": "quantity"}
}
]},
{
"id": PRODUCT_GROUP_ID,
"products": [
{
"name": "Google Pixel",
"counterparty_lock": false,
"description": "The best Pixel yet.",
"price_1": {"base_amount": {"amount": "20000"}, "discount_amount": {"amount": "100.00"}},
"price_2": {"base_amount": {"amount": "1000"}, "discount_percent": "5"},
"quantity": {"amount": 1, "type": "multiple_choice"}
},
{
"name": "5G cell phone plan",
"counterparty_lock": true,
"description": "Unlimited calls and data.",
"price_1": {"base_amount": {"amount": "99.99"}},
"quantity": {"amount": 0, "type": "single_choice"}
},
{
"name": "Cell phone insurance",
"counterparty_lock": false,
"description": "Protect your device!",
"price_1": {"base_amount": {"amount": "9.99"}},
"quantity": {"amount": 5, "type": "quantity"}
}
]}
]
}'
This command should result in a contract with the following product tables:
Expected response
{
...
"product_groups": [
{
"_private_ownerside": {
"created_time": "2023-09-12T09:39:12+00:00",
"custom_id": null,
"updated_time": "2023-09-12T09:39:12+00:00"
},
"configuration": {
"columns": [
{
"enabled": true,
"key": "name",
"label": "Product"
},
{
"enabled": true,
"key": "description",
"label": "Description"
},
{
"enabled": true,
"key": "price_1",
"label": "Price 1"
},
{
"enabled": true,
"key": "price_2",
"label": "Price 2"
},
{
"enabled": true,
"key": "count",
"label": "Value"
}
],
"counterpart_edit": true,
"hide_price_summation": false,
"name": {
"enabled": false,
"label": "Untitled"
},
"price_affixes": {
"postfix": "",
"prefix": ""
},
"price_precision": 2,
"quantity_precision": 0
},
"created_from": 60259152,
"enabled_columns": [
{
"enabled": true,
"key": "name"
},
{
"enabled": true,
"key": "description"
},
{
"enabled": true,
"key": "price_1"
},
{
"enabled": true,
"key": "price_2"
},
{
"enabled": true,
"key": "count"
}
],
"id": 60635062,
"products": [
{
"_private_ownerside": {
"created_time": "2023-09-12T09:39:12+00:00",
"custom_id": null,
"updated_time": "2023-09-12T09:39:12+00:00"
},
"counterparty_lock": false,
"created_from": null,
"description": "The smartest watch on the market.",
"id": 195178227,
"name": "Swatch Smart Watch",
"price_1": {
"amount": {
"amount": "19900.00"
},
"base_amount": {
"amount": "20000.00"
},
"discount_amount": {
"amount": "100.00"
},
"discount_percent": "0.000"
},
"price_2": {
"amount": {
"amount": "950.00"
},
"base_amount": {
"amount": "1000.00"
},
"discount_amount": {
"amount": "0.00"
},
"discount_percent": "5.000"
},
"quantity": {
"amount": 1,
"type": "multiple_choice"
}
},
{
"_private_ownerside": {
"created_time": "2023-09-12T09:39:12+00:00",
"custom_id": null,
"updated_time": "2023-09-12T09:39:12+00:00"
},
"counterparty_lock": true,
"created_from": null,
"description": "Insure your watch for an additional 2 years!",
"id": 195178228,
"name": "Smart insurance",
"price_1": {
"amount": {
"amount": "99.99"
},
"base_amount": {
"amount": "99.99"
},
"discount_amount": {
"amount": "0.00"
},
"discount_percent": "0.000"
},
"price_2": {
"amount": {
"amount": "0.00"
},
"base_amount": {
"amount": "0.00"
},
"discount_amount": {
"amount": "0.00"
},
"discount_percent": "0.000"
},
"quantity": {
"amount": 0,
"type": "single_choice"
}
},
{
"_private_ownerside": {
"created_time": "2023-09-12T09:39:12+00:00",
"custom_id": null,
"updated_time": "2023-09-12T09:39:12+00:00"
},
"counterparty_lock": false,
"created_from": null,
"description": "Protect your watch face!",
"id": 195178229,
"name": "Smart screen cover",
"price_1": {
"amount": {
"amount": "9.99"
},
"base_amount": {
"amount": "9.99"
},
"discount_amount": {
"amount": "0.00"
},
"discount_percent": "0.000"
},
"price_2": {
"amount": {
"amount": "0.00"
},
"base_amount": {
"amount": "0.00"
},
"discount_amount": {
"amount": "0.00"
},
"discount_percent": "0.000"
},
"quantity": {
"amount": 5,
"type": "quantity"
}
}
]
},
{
"_private_ownerside": {
"created_time": "2023-09-12T09:39:12+00:00",
"custom_id": null,
"updated_time": "2023-09-12T09:39:12+00:00"
},
"configuration": {
"columns": [
{
"enabled": true,
"key": "name",
"label": "Product"
},
{
"enabled": true,
"key": "description",
"label": "Description"
},
{
"enabled": true,
"key": "price_1",
"label": "Price 1"
},
{
"enabled": true,
"key": "price_2",
"label": "Price 2"
},
{
"enabled": true,
"key": "count",
"label": "Value"
}
],
"counterpart_edit": true,
"hide_price_summation": false,
"price_affixes": {
"postfix": "",
"prefix": ""
},
"price_precision": 2,
"quantity_precision": 0
},
"created_from": 60259153,
"enabled_columns": [
{
"enabled": true,
"key": "name"
},
{
"enabled": true,
"key": "description"
},
{
"enabled": true,
"key": "price_1"
},
{
"enabled": true,
"key": "price_2"
},
{
"enabled": true,
"key": "count"
}
],
"id": 60635063,
"products": [
{
"_private_ownerside": {
"created_time": "2023-09-12T09:39:12+00:00",
"custom_id": null,
"updated_time": "2023-09-12T09:39:12+00:00"
},
"counterparty_lock": false,
"created_from": null,
"description": "The best Pixel yet.",
"id": 195178230,
"name": "Google Pixel",
"price_1": {
"amount": {
"amount": "19900.00"
},
"base_amount": {
"amount": "20000.00"
},
"discount_amount": {
"amount": "100.00"
},
"discount_percent": "0.000"
},
"price_2": {
"amount": {
"amount": "950.00"
},
"base_amount": {
"amount": "1000.00"
},
"discount_amount": {
"amount": "0.00"
},
"discount_percent": "5.000"
},
"quantity": {
"amount": 1,
"type": "multiple_choice"
}
},
{
"_private_ownerside": {
"created_time": "2023-09-12T09:39:12+00:00",
"custom_id": null,
"updated_time": "2023-09-12T09:39:12+00:00"
},
"counterparty_lock": true,
"created_from": null,
"description": "Unlimited calls and data.",
"id": 195178231,
"name": "5G cell phone plan",
"price_1": {
"amount": {
"amount": "99.99"
},
"base_amount": {
"amount": "99.99"
},
"discount_amount": {
"amount": "0.00"
},
"discount_percent": "0.000"
},
"price_2": {
"amount": {
"amount": "0.00"
},
"base_amount": {
"amount": "0.00"
},
"discount_amount": {
"amount": "0.00"
},
"discount_percent": "0.000"
},
"quantity": {
"amount": 0,
"type": "single_choice"
}
},
{
"_private_ownerside": {
"created_time": "2023-09-12T09:39:12+00:00",
"custom_id": null,
"updated_time": "2023-09-12T09:39:12+00:00"
},
"counterparty_lock": false,
"created_from": null,
"description": "Protect your device!",
"id": 195178232,
"name": "Cell phone insurance",
"price_1": {
"amount": {
"amount": "9.99"
},
"base_amount": {
"amount": "9.99"
},
"discount_amount": {
"amount": "0.00"
},
"discount_percent": "0.000"
},
"price_2": {
"amount": {
"amount": "0.00"
},
"base_amount": {
"amount": "0.00"
},
"discount_amount": {
"amount": "0.00"
},
"discount_percent": "0.000"
},
"quantity": {
"amount": 5,
"type": "quantity"
}
}
]
}
]
}
Response codes
Status | Meaning | Description |
---|---|---|
200 | OK | Returns the created contract. |
400 | Bad Request | Invalid format or content of the request. |
404 | Not Found | A required entity is missing. |
409 | Conflict | A conflict occurred with the current state of the target resource. |
Updated about 13 hours ago