Creating custom object with unique ID

Hey everyone,
I have a custom object with a unique ID. Hence I cant create a record without providing an ID.
I would like for my clients to create records using forms (or any other automated way). I cant create the object without the ID.

If I add the ID the person would need to use a number that hasnt been used in order to create a contact, or they will change existing records. Thats a no go.
Does anyone have a workaround on how I am able to create a record via forms?
One “solution” I would have is to mirror all properties at the contact and have a workflow create a record with the consecutive number but I dont know how to create consecutive numbers either.

Please let me know if you need additional context.

Hi @CElis,

Thanks for reaching out to the Community!

I wanted to invite our subject matter experts to see if they have insight.

Hi @Teun, @louischausse, @johnelmer - Do you have any advice for @CElis?

Thank you!

Best,

Kristen

Hi @kvlschaefer
I think these two answers can be marked as solutions:
https://community.hubspot.com/t5/CRM/Creating-custom-object-with-unique-ID/m-p/823967/highlight/true#M141836
https://community.hubspot.com/t5/CRM/Creating-custom-object-with-unique-ID/m-p/828184/highlight/true#M142049
Thanks

Hey @CElis ,
Happy to help but I will need extra context.

  1. The unique ID property you are mentionning. Is it different from the unique HubSpot Record ID?
  2. The form you mentionning, is it a form on a webpage or the internal object record creation form?
  3. Is there a reason why you set that property as required to create the record? You could set it as unnecessary and generate the unique id with a workflow on record creation.

Thanks for reaching out.
The object in question is for a trader. On the one hand we have a custom object for the “supplier offer”, on the other we have a custom object for the “customer needs”. The trader will match the offers with needs, buy from the supplier and sell to the customer. (It is a bit more complicated but this is the gist of it.)
1. Yes. The intention was that every record has consecutive number. Also they have less digits than the record ID making it easier to work with.

2. The intention is that the supplier and the customer respectivly can create a new offer (a record for supplier offer) or a need (a new record for customer needs)
3. I set it as required as to not have mulitple records with the same ID. This was supposed to help with confusion and sending out false e-mails to clients. If you can help me generating unique IDs i’d be much appreciated.
Please note that we are currently working in Sales Enterprise and operations starter. While we might be able to upgrade it is not planned right now.

Thank you for your help.

Hi @CElis ,
Well, the only way I know to generate a serial id is by using a custom coded action in a workflow which is available with Operations Hub Pro and Enterprise.

  1. Set the id property as optionnal
  2. Set it as not editable by users (assign it to super admins only or view only)
  3. Use the code in this github repo to create your custom coded action: GitHub - Auxilio-io/generate-a-serial-hubspot-object-number-unique-id-based-on-previous-object: Object Ids in HubSpot are randomly generated. This custom coded action lets you generate an incremented number id. · GitHub
  4. If you want help to upgrade to Operations Hub Pro at a discounted price, schedule a call using the button in my signature.

Alternatively, if you can’t upgrade to Ops Hub Pro you can try doing the same with a third party like Zapier, Make, Tray.io, etc.
Don’t forget to mark my reply as a solution if you are satisfied. If not, do not hesitate to ask me anything!

Thanks for the input.

Do you have any idea how it could be managed via Zapier?

Hi @CElis
This Zapier community post suggest how to do it

Don’t forget to mark my reply as a solution if you are satisfied. If not, do not hesitate to ask me anything!

Thanks for the information. I learned something new and tested it.
Sadly it seems to fail at the trigger, as I can not use custom objects as triggers.
In addition I dont seem to be able to influence custom objects so I would not be able to change the number anyways.
Am I missing something?

You are right I just checked and Zapier isn’t compatible with HubSpot Custom objects. Sorry, I forgot about that.
What you could do is build a custom object-based workflow with your desired triggers and send an internal email notification to a specific address
And then trigger your zap with Email parser by Zapier : Email Parser by Zapier
And finaly use Code by Zapier to push the unique id to HubSpot custom object property using HubSpot’s custom object api Code by Zapier Integrations | Connect Your Apps with Zapier

Don’t forget to mark my reply as a solution if you are satisfied. If not, do not hesitate to ask me anything!

Working on implmenting this as well, so thank you for the solution. Hoping you can help me out as well.
I have the following…
Private app: TERMS_CREDIT_RECORD_ID_GENERATOR
Custom Object: Terms/Credit Application
Number Property on the Custom Object: Application ID with application_id as the internal name
I’m getting the following error…

Workflow config is the following…

@tjcrawford please copy paste your code if you want me to help :slightly_smiling_face:

I updated the Custom Code to use Node.js 16.x and HubSpot Client v8.
Error here

LAMBDA_WARNING: Unhandled exception. The most likely cause is an issue in the function code. However, in rare cases, a Lambda runtime update can cause unexpected function behavior. For functions using managed runtimes, runtime updates can be triggered by a function change, or can be applied automatically. To determine if the runtime has been updated, check the runtime version in the INIT_START log entry. If this error correlates with a change in the runtime version, you may be able to mitigate this error by temporarily rolling back to the previous runtime version. For more information, see https://docs.aws.amazon.com/lambda/latest/dg/runtimes-update.html
[ERROR] KeyError: 'email'
Traceback (most recent call last):
  File "/var/task/hubspotHandler.py", line 6, in hubspot_handler
    return file.main(event)
  File "/var/task/file.py", line 3, in main
    email = event["inputFields"]["email"]
Memory: 31/128 MB
Runtime: 32.55 ms

Code here…

const hubspot = require(‘@hubspot/api-client’);

exports.main = async (event, callback) => {

//define variables

const opsToken = process.env.TERMS_CREDIT_RECORD_ID_GENERATOR

var allRecords = [];

const objectType = “TERMS/CREDIT APPLICATIONS”; // This is the type id of the custom object used in this example. Could be replaced with any standard object (contacts, deals, companies, tickets) or another custom object type id 2-XXXXX

const limit = 100;

var after = undefined;

const properties = [“application_id”]; // This is the name of your serial number property. This property needs to be created on the object first.

const archived = false;

var hasMore = true;

const recordId = event.inputFields[‘hs_object_id’];

const createdate = event.inputFields[‘hs_createdate’];

//define reusable function

const hubspotClient = new hubspot.Client({“accessToken”:opsToken});

async function listRecords(objectType, limit, after, properties, archived) {

try {

const apiResponse = await hubspotClient.crm.objects.basicApi.getPage(objectType, limit, after, properties, archived);

return apiResponse;

} catch (e) {

if (e.response) {

console.error(JSON.stringify(e.response, null, 2));

} else {

console.error(e);

}

}

}

// get all records

while (hasMore) {

const recordsPage = await listRecords(objectType, limit, after, properties, archived);

if (recordsPage && recordsPage.results && recordsPage.results.length > 0) {

allRecords.push(…recordsPage.results);

}

if (recordsPage.paging && recordsPage.paging.next) {

console.log(“There is another page”);

after = recordsPage.paging.next.after;

}

else {

console.log(“There are no more pages”);

hasMore = false;

}

}

// remove the record enrolled in this workflow from the list

const allRecordsExceptTheCurrent = allRecords.filter(function(record) {

return record.id !== recordId;

});

if (allRecordsExceptTheCurrent.length > 0) {

// get latest number

const latestRecords = allRecordsExceptTheCurrent.reduce((latest, current) => {

const currentCreateDate = Date.parse(current.properties.hs_createdate);

const latestCreateDate = parseInt(createdate);

// Check if the record was created before the specified createdate

if (currentCreateDate < latestCreateDate) {

// Update the latest record if it’s empty or if the current record was created more recently

if (!latest || currentCreateDate > Date.parse(latest.properties.hs_createdate)) {

latest = current;

}

}

return latest;

}, null);

var latestRecordId = latestRecords.id

var latestRecordNumber = latestRecords.properties.serial_number_id

if (latestRecordNumber) {

console.log(`Latest number = ${latestRecordNumber} and ID = ` + latestRecordId)

const recordNumber = parseInt(latestRecordNumber) + 1;

console.log(`New number = ` + recordNumber);

callback({

outputFields: {

latestRecordId: latestRecordId,

recordNumber: recordNumber,

nextAction: “setRecordNumber”

}

});

} else {

callback({

outputFields: {

latestRecordId: latestRecordId,

recordNumber: “NaN”,

nextAction: “retry”

}

});

}

} else {

console.error(“No records found”);

}

}

this is a python error… Make sure you selected nodejs in the dropdown… not python.

Hi, start by trying to change the HubSpot client v11 to v8 :slightly_smiling_face:

Hey @louischausse ,
just in case you havent seen. With a new product update zapier now supports custom objects.

Question, would this also be possible if we didn’t want to use a randomly generator number rather provide a list of numbers that can be used?

Hello,
What the code above is doing is checking the previous record created id and +1. So if the latest record created has an id of “1000” the next created will be “1001”.
If you would like the id to be selected in a list of available ids that are not sequential, we would need to modify this code so it go checks a list of available ids in a repository. This could be a HubDB if you want your solution to be a 100% HubSpot-based, but it could also be any other DB that can be queried by an API call.
Do not hesitate to ask me anything!

Hey Louis,

I am attempting to run the code you have generously created and it seems to be throwing errors in the logs. I have taken classes in coding but don’t have a ton of experience with API calls. Is there a missing step in your readme about updating a variable with the secret we created in our private app or something to that affect?

WARNING: The logs for this function have exceeded the 4KB limit.
...
GuY3Ip3VUnRs\"}],\"group\":\"cf-nel\",\"max_age\":604800}","server":"cloudflare","strict-transport-security":"max-age=31536000; includeSubDomains; preload","vary":"origin, Accept-Encoding","x-content-type-options":"nosniff","x-envoy-upstream-service-time":"2","x-evy-trace-listener":"listener_https","x-evy-trace-route-configuration":"listener_https/all","x-evy-trace-route-service-name":"envoyset-translator","x-evy-trace-served-by-pod":"iad02/hubapi-td/envoy-proxy-5b5c96c966-ff5vt","x-evy-trace-virtual-host":"all","x-hubspot-auth-failure":"401 Unauthorized","x-hubspot-correlation-id":"e8937665-6336-4454-be8e-965ec6dc6822","x-request-id":"e8937665-6336-4454-be8e-965ec6dc6822","x-trace":"2BC8475EF4EC1D5AD62FE8707DBAF441C8E27C4982000000000000000000"}
 at BasicApiResponseProcessor.<anonymous> (/opt/nodejs/node_modules/@hubspot/api-client/lib/codegen/crm/objects/apis/BasicApi.js:285:23)
 at Generator.next (<anonymous>)
 at fulfilled (/opt/nodejs/node_modules/@hubspot/api-client/lib/codegen/crm/objects/apis/BasicApi.js:5:58)
 at processTicksAndRejections (node:internal/process/task_queues:96:5) {
 code: 401,
 body: {
 status: 'error',
 message: 'Authentication credentials not found. This API supports OAuth 2.0 authentication and you can find more details at https://developers.hubspot.com/docs/methods/auth/oauth-overview',
 correlationId: 'e8937665-6336-4454-be8e-965ec6dc6822',
 category: 'INVALID_AUTHENTICATION'
 },
 headers: {
 'access-control-allow-credentials': 'false',
 'cf-cache-status': 'DYNAMIC',
 'cf-ray': '82220df6ed0405de-IAD',
 connection: 'close',
 'content-length': '299',
 'content-type': 'application/json;charset=utf-8',
 date: 'Tue, 07 Nov 2023 02:13:00 GMT',
 nel: '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}',
 'report-to': '{"endpoints":[{"url":"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=qPirBjF34VL0vIegXr06HATQZxyYBFkn9duKefhIUirutxyM0oEB9rVJdRzE6zdqoPBMOdaIfwtkXQC6d0Wso7oRV9CK9oApBFIHZq0QpMuQPKzr7E6BGuY3Ip3VUnRs"}],"group":"cf-nel","max_age":604800}',
 server: 'cloudflare',
 'strict-transport-security': 'max-age=31536000; includeSubDomains; preload',
 vary: 'origin, Accept-Encoding',
 'x-content-type-options': 'nosniff',
 'x-envoy-upstream-service-time': '2',
 'x-evy-trace-listener': 'listener_https',
 'x-evy-trace-route-configuration': 'listener_https/all',
 'x-evy-trace-route-service-name': 'envoyset-translator',
 'x-evy-trace-served-by-pod': 'iad02/hubapi-td/envoy-proxy-5b5c96c966-ff5vt',
 'x-evy-trace-virtual-host': 'all',
 'x-hubspot-auth-failure': '401 Unauthorized',
 'x-hubspot-correlation-id': 'e8937665-6336-4454-be8e-965ec6dc6822',
 'x-request-id': 'e8937665-6336-4454-be8e-965ec6dc6822',
 'x-trace': '2BC8475EF4EC1D5AD62FE8707DBAF441C8E27C4982000000000000000000'
 }
}
2023-11-07T02:13:00.824Z	ERROR	Unhandled Promise Rejection 	{"errorType":"Runtime.UnhandledPromiseRejection","errorMessage":"TypeError: Cannot read properties of undefined (reading 'paging')","reason":{"errorType":"TypeError","errorMessage":"Cannot read properties of undefined (reading 'paging')","stack":["TypeError: Cannot read properties of undefined (reading 'paging')"," at Object.exports.main (/var/task/file.js:39:22)"," at processTicksAndRejections (node:internal/process/task_queues:96:5)"]},"promise":{},"stack":["Runtime.UnhandledPromiseRejection: TypeError: Cannot read properties of undefined (reading 'paging')"," at process.<anonymous> (file:///var/runtime/index.mjs:1276:17)"," at process.emit (node:events:513:28)"," at emit (node:internal/process/promises:140:20)"," at processPromiseRejections (node:internal/process/promises:274:27)"," at processTicksAndRejections (node:internal/process/task_queues:97:32)"]}
Unknown application error occurred
Runtime.Unknown