Hello, I have a problem related to this endpoint:
/crm/objects/v3/invoices/batch/update
When I attempt to batch update more than 20 invoices at a time I get the following error:
{“status”:“error”,“message”:“There was an error processing the request.”,“correlationId”:“942e1f44-64d2-444c-b010-f138568a639c”,“category”:“INTERNAL_ERROR”}
Does anyone have an idea why this is?
I am guessing its a bug within the API because the lesser invoices updated in batch the less I see it.
Hi @SNSDan and welcome, we are so glad you are here!
Thanks for reaching out to the HubSpot Community!
Here are some resources for reference:
- Update a batch of invoices by internal ID, or unique property values
- Using Object APIs
Let’s check with our Top Experts: Hi @sylvain_tirreau, @GRajput and @AHernández60 do you experience the same? Do you have any suggestions to help @SNSDan, please?
Have a lovely day and thanks so much!
Bérangère
Hi @DStoynev
These kind of error messages are common when a property being sent does not exist, is read-only, or does not have an equivalent value in HubSpot (in the case of Choosing Option properties).
You can probably find more information in the application logs by filtering for “error 500” (5XX).
If you like, share an example of the batch you are trying to insert and/or the log provided by the application, and I will try to help you fix it (remember to replace any sensitive information, but keep the value of the choosing option properties unchanged so that the error can be better detected). You can also send me a private message if you prefer to share the information privately.
I look forward to helping you.
Best regards
Moderator note: While this solution may not address the original poster’s specific situation, it could be helpful for other community members facing similar challenges.
Hi @AHernández60 thank you for the reply.
We are still in testing so no sensitive customer info.
here is the most simple example I have in the logs of a payload I sent:
Request:
{“inputs”:[{“id”:“892844799213”,“properties”:{“hs_invoice_status”:“paid”}},{“id”:“892836937963”,“properties”:{“hs_invoice_status”:“paid”}},{“id”:“892844799197”,“properties”:{“hs_invoice_status”:“paid”}},{“id”:“892844799202”,“properties”:{“hs_invoice_status”:“paid”}},{“id”:“892844799206”,“properties”:{“hs_invoice_status”:“paid”}},{“id”:“892836937958”,“properties”:{“hs_invoice_status”:“paid”}},{“id”:“892844799212”,“properties”:{“hs_invoice_status”:“paid”}},{“id”:“892844799196”,“properties”:{“hs_invoice_status”:“paid”}},{“id”:“892844799198”,“properties”:{“hs_invoice_status”:“paid”}},{“id”:“892836937961”,“properties”:{“hs_invoice_status”:“paid”}},{“id”:“892844799203”,“properties”:{“hs_invoice_status”:“paid”}},{“id”:“892844799209”,“properties”:{“hs_invoice_status”:“paid”}},{“id”:“892836937966”,“properties”:{“hs_invoice_status”:“paid”}},{“id”:“892836937952”,“properties”:{“hs_invoice_status”:“paid”}},{“id”:“892844799201”,“properties”:{“hs_invoice_status”:“paid”}},{“id”:“892836937957”,“properties”:{“hs_invoice_status”:“paid”}},{“id”:“892844799210”,“properties”:{“hs_invoice_status”:“paid”}},{“id”:“892836937959”,“properties”:{“hs_invoice_status”:“paid”}},{“id”:“892836937967”,“properties”:{“hs_invoice_status”:“paid”}},{“id”:“892844799200”,“properties”:{“hs_invoice_status”:“paid”}}]}
Hubspot logs dont appear to store the whole payload I am adding it again for reference here and I can provide a whole example payload as well here from our server logs its not the exact request but we have the same error response:
[
{ id: ‘892446547177’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437359862’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437359860’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446547172’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446548156’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446547192’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446547191’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446547188’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446547185’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437360827’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446547190’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437359864’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446548154’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446548158’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437360832’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437360830’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437359859’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446547186’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446548159’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446547193’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446547175’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437359861’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437359851’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446547174’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446547170’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437359857’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446547181’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446547176’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446547179’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446547184’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446547187’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446547182’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446547178’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446548155’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446548157’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437359858’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437359855’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437359852’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437360837’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446547171’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446547173’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446547180’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437360831’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437360829’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446547183’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892446547189’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437360826’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444660932’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437359863’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437359865’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444660936’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437360828’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444660938’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444659954’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437359856’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444659956’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444660927’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444660924’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444660931’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444660929’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444660941’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444660935’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444660942’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444660930’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444660933’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444660925’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437359853’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444659961’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444659958’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444659959’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444659955’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444660940’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444660939’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437360833’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437360835’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444660928’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437359854’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444660934’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444660923’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444660922’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444660926’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437360834’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892437360836’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444659960’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444659957’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444660943’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892444660937’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892514285817’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892514285815’, properties: { hs_invoice_status: ‘paid’ } },
{ id: ‘892514285816’, properties: { hs_invoice_status: ‘paid’ } }
]
Response is what I sent before:
Response Headers:
{
“Content-Type”: [
“{\“type\”:\“application\”,\“subtype\”:\“json\”,\“parameters\”:{\“charset\”:\“UTF-8\”},\“wildcardType\”:false,\“wildcardSubtype\”:false}”
],
“X-HubSpot-RateLimit-Interval-Milliseconds”: [
“10000”
],
“X-HubSpot-RateLimit-Remaining”: [
“103”
],
“X-HubSpot-RateLimit-Max”: [
“110”
],
“X-HubSpot-RateLimit-Secondly”: [
“11”
],
“X-HubSpot-RateLimit-Secondly-Remaining”: [
“10”
]
}
Reponse Body:
{“status”:“error”,“message”:“There was an error processing the request.”,“correlationId”:“76747982-91fa-4154-8c4f-e067474949f4”,“category”:“INTERNAL_ERROR”}
I know that this property is working because when I work normally its ok and its valid.
I saw this issue while stress testing a hubspot syncronization microservice I have which respects the hubspot rate limits per portalId. I send 1 request per second per portal.
It works fine with 20 per batch 99.9 percent of the time and when its more like 30 per batch its fails pretty much every time. The request im showing you is for 20 per batch one of the few instances. Is there something im not doing correctly or is it a hubspot bug?
Kind Regards,
Daniel
Hi Daniel @SNSDan
Researching and studying the invoice documentation, I suspect what may be happening. To verify this, I created a small node application that created 50 invoices and attempted to update them, with mixed results.
Apparently, the hs_invoice_status field has certain peculiarities. Although it is available for updating via API, it requires that other properties and associations of the object be fulfilled. You can see it here in the documentation. The paragraph about marking them as “open” gives us these clues:
“Additionally, the invoice will inherit other property values when you later associate a contact with it, such as contact and company details, which will be required before you can set the invoice to the Open state. Learn more about required properties and associations.”
Try calling a batch of only 2-3 elements. IT returns a quite clear error:
“Do not have the proper amount of associations of type INVOICE_TO_LINE_ITEM to finalize this invoice. Number needed: must be > 0.”
At least in my case, if I try to update other invoice properties (hs_number for example), I have no problem updating 20 or 50 (by the way, the limit per batch is 100 objects).
I hope this helps you solve the problem. If so, I would appreciate it if you could mark this question as resolved so that other colleagues can see the solution. If you continue to have problems or need me to expand on the details by doing some more testing, please let me know.
Regards,
Ander.
Moderator note: While this solution may not address the original poster’s specific situation, it could be helpful for other community members facing similar challenges.
Hi @AHernández60 unfortunately this is not the case for me thank you for taking the time. In my case if I try with 1-2 invoices it works perfectly. as mentioned even on up to 20 batched requests it happens intermittently and succeeds on retry. I already have associaitons in place contact is mandatory, company is not I already respect that. I have line items associated as well before attempting to set the status to paid. it really starts failing when I go above 20 consistently otherwise its a success. I taught maybe the payload is too big but considering in the example ive sent you I only use 1 property to update its not that either.
Regards,
Daniel.
Hello @SNSDan
I’m sorry to heard that.
You mentioned that you were making only one request per second. Is it possible that you are performing some other type of query in addition to the insertion? Such as a search, for example? As you probably know, the limit for searches is different from that for other types of requests. I don’t know if there is a specific limit for batch requests (as far as I know, there is no difference, and I haven’t seen any references to this in the documentation).
Even so, I don’t think that’s the case since you have a 500 error and not a 401 error, and I imagine there are no problems with authentication, but I’m asking just in case.
assume you have a “batch sending loop” in which you control those requests at 1 per second. To perform an arbitrary test and see if we’re getting closer, have you tried increasing this timeout to, say, 5 seconds?
Best regards
The rate limits are visible in the response headers and its not even close.
There are no authentication errors its only 500. I handle token expiration updating before making a request. I have not tried increasing to 5 seconds because it does not make sense considering there are clearly defined rate limits. I actually got another idea from your first recommendations just now. I am moving the invoice status from draft to paid. I will try to see if moving from draft to open to paid might do the trick as well because maybe there could be some extra processing done during open for the invoice and I will try to increase the timeout just in case but doubtful of that because the response headers shows that we have not hit the rate limit.
Hi @SNSDan
As you mentioned, since it was a 500 error, it was very unlikely that there was an authentication problem, but I suggested both this and increasing the timeout to 5 seconds in case there was some obscure logic in the batch update.
Please let me know the results you get in case we can help you or to learn from for future similar cases.
Regards,
Ander
Hi Ander, I tested what I described first I tried to change the invoice status first to open and when a second later to paid with a batch of 50 invoices this didnt work. the exception is again thrown on the first possible status change and in this case on open instead of paid.
I got rid of it again and tried sending each request every 5 seconds as you suggested and it was still the same unfortunately. I still reverted back to my original logic which was sending in a batch of 20 invoices with just 1 second delay and again its working without an issue. Its definetely not an auth problem since im making requests every second and it would have been seen on other requests as well like line item creation or original invoice creation. I guess I will stick with the 20 per batch as I personally dont have any other ideas and this works. If you have any more ideas id be happy to try.
Hi
Although I haven’t been able to reproduce the error, I think it would be the case to contact HubSpot support directly, as they can sometimes provide more information about those 500 errors from their end.
In any case, we have the case to expand testing, and if we discover anything new, I will let you know.
Regards
Thank you for all the help Ander.
Regards,
Daniel.
Hi @SNSDan
The batch limit is officially 100, so it should work fine. However, since it works with 20 records but fails with 30, the issue might be caused by some incorrect values in your update payload. Please review your payload to ensure all values are valid. If everything looks correct, I recommend reaching out to HubSpot Support, as they will be able to assist you further.
I hope this will help you out. Please mark it as Solution Accepted and upvote to help another Community member.
Thanks!
Thank you for the suggestion @GRajput.
My payload seems correct and is all based on the hubspot documentation.
I will reach out to support in hopes of getting a resolution.
Regards,
Daniel.
SNS Software
Hi @SNSDan You’re right that the batch write limit is 100, so >20 shouldn’t fail on its own.
Two things usually trigger intermittent 500s on invoices: a strict status state machine and concurrent mutations. First, confirm every record in the batch satisfies invoice prerequisites before the status jump (associations, line items, amounts).
HubSpot’s invoice object enforces rules on transitions like Draft > Open >Paid and will error if any item is not eligible, which can topple the whole batch (Accounts Dashboard | HubSpot )
Second, avoid racing the same invoice via parallel jobs; lock your worker per invoice ID, add jittered backoff on 5xx, and chunk consistently (e.g., 20–30) rather than varying sizes.
As a diagnostic, try a batch that mixes 5 known-good IDs with 1 intentionally invalid status change; if that reproduces the 500, switch to per-item retry on 207-style partial responses or fall back to single updates for the offenders (Accounts Dashboard | HubSpot ) If consistency across systems is the goal, Stacksync keeps HubSpot and your finance app mirrored in real time without brittle batch windows.
Hi Ruben,
As mentioned in my earlier posts, I only update invoices after confirming that all required associations are valid — both at the contact level and for the line items. I’ve built a synchronization service that processes invoices in batches per portalId, which keeps everything within rate limits. It also ensures that the same invoice is never updated twice, since it follows the full invoice-creation flow and uses traceIds to verify that no previous operations have failed.
All steps in the flow are fully awaited before proceeding, and a retry mechanism handles any transient failures. I’m currently processing 20 invoices per batch, and this setup has been working reliably. Even when I increase the batch size and add a longer wait time, the issue still persists. I’ll review any additional invoice properties that might be restricted from being updated, as that could be contributing to the problem.
In any case, I’ll go through your suggestions as well — this is a new service that hasn’t been deployed live yet, so it’s very possible I’ve overlooked something.
Thank you.
SNS Software LTD
Technical Director
Email: dan@simply-neat.com
Website: www.sns-software.com
Official Worldpay payment solutions partner.
Looking for UK based HubSpot partners interested in collaboration.
Hi @SNSDan and thanks for getting back to us!
Batch operations are limited to 100 records maximum per request according to the CRM Contacts guide.
While you’re processing 20 invoices per batch (well within limits), the issue may relate to:
- Read-only properties: Attempting to update read-only or non-existent properties will result in errors. The documentation states that “provided property values will be overwritten. Read-only and non-existent properties will result in an error.”
- Enhanced error messages: HubSpot now provides detailed property validation errors in a new “errors” field to help identify which specific properties are causing issues.
Check your error responses for the new structured error format that includes property-specific validation failures.
This should help pinpoint which invoice properties are restricted from updates.
Also, here are some documentation that might help:
- Update a batch of invoices by internal ID, or unique property values
- Update endpoint
I hope this helps!
Have a great day!
Bérangère
This post was created with the assistance of AI tools.
Hi @SNSDan , appreciate how thoroughly you’ve stress-tested this and documented the payloads.
When a clean batch like your hs_invoice_status: paid example still throws a 500, that is usually less about validation and more about something brittle in the internal state machine for invoices rather than your JSON itself.
HubSpot’s docs confirm the 100 object batch limit for CRM object updates, and invoice updates are supposed to behave the same way as other CRM objects in that regard, with failures normally bubbling up as field-level validation errors instead of a generic internal error (Understanding the CRM APIs - HubSpot docs )
The fact that retries succeed with the same payload at 20 but then fall over at 30 is a strong signal that you have hit an edge case on their side, not only a bad property value. If you want to push this a bit further before settling on “20 is the safe ceiling,” one trick is to toggle the same test set through the single update endpoint first to see if any specific IDs consistently fail outside of batch, then replay those IDs in a smaller batch to compare responses (Accounts Dashboard | HubSpot )
Logging the correlationId per failing batch and handing that to support usually gets you a more concrete answer from their internal logs than what we see from the 500 body. If the longer term goal is just to keep invoice statuses aligned with your accounting or billing system without fighting these batch quirks, Stacksync keeps HubSpot and your finance app mirrored as changes happen so you rely less on heavy batch updates and more on steady, real-time sync.
